<polymer-element name="jso-attribute-render-color-table"
                 attributes="displayProperty attributeManager defaultValue visualSet allowListParse">
    <template>
        <link rel="stylesheet" href="../../jso-style.css">
        <link rel="stylesheet" href="../../jso-panel.css">
        <link rel="stylesheet" href="../../core-list-table.css">
        <style>
            :host {
                display: block;
                position: absolute;
                box-sizing: border-box;
                background-color: #FFFFFF;

                top: 0px;
                right: 320px;
                width: 500px;
                transition: all 0.2s;
            }

            .container {
                box-sizing: border-box;
                padding: 2px 5px 5px 5px;
            }

            .footer > * {
                margin-left: 5px;
            }

            #left {
                width: 165px;
                margin-right: 10px;
            }

            .selbox {
                box-sizing: border-box;
                overflow-y: auto;
                border: 1px solid #d3d3d3;
                background-color: #FFF;
            }

            .selitem {
                padding: 2px 5px;
            }

            .selitem[data-checked=true] {
                background-color: #ddd;
            }

            core-list {
                height: 175px;
                border: 1px solid #d3d3d3;
                border-top-width: 0;
                background-color: #FFFFFF;
            }

            #colorLegend {
                border: 1px solid #aaaaaa;
                width: 50px;
                margin-top: 3px;
            }

            .colorbox {
                outline: 0;
                width: 20px;
                border: 1px solid #d3d3d3;
                border-right: 0;
            }

            jso-color-menu {
                transition: opacity 0.1s, visibility 0.1s;
            }

            jso-color-menu[hide=true] {
                visibility: hidden;
                opacity: 0;
            }

            jso-color-menu[hide=false] {
                visibility: visible;
                opacity: 1;
            }
        </style>
        <div class="panel panel-shadow">
            <div class="header">
                <div class="text">{{displayProperty}} rendering configuration</div>
                <div class="headeractions" horizontal end-justified layout flex>
                    <div class="text headerclose" on-click="{{handleClose}}"></div>
                </div>
            </div>
            <div class="container" horizontal layout>
                <div id="left" vertical layout>

                    <label>Attribute name</label>

                    <div class="selbox" style="height: 100px;">
                        <template repeat="{{column in attributeManager.columns}}">
                            <div horizontal layout>
                                <div class="selitem" flex
                                     data-checked="{{ attributeName == column.name}}"
                                     data-name="{{column.name}}"
                                     on-click="{{handleAttributeNameSelect}}">
                                    {{column.title}}
                                </div>
                            </div>
                        </template>
                    </div>

                    <label style="margin-top:8px;">Data type</label>

                    <div class="selbox">
                        <div flex class="selitem" data-checked="{{attributeType == 'discrete'}}"
                             on-mousedown="{{handleAttributeTypeSelect}}" data-name="discrete">Categorical
                        </div>
                        <div flex class="selitem" data-checked="{{attributeType == 'continuous'}}"
                             on-mousedown="{{handleAttributeTypeSelect}}" data-name="continuous">Continuous
                        </div>
                    </div>

                    <template if="{{allowListParse == 'true'}}">
                        <label style="margin-top:8px;">Parse data as</label>

                        <div class="selbox">
                            <div flex class="selitem" data-checked="{{attributeParse == 'string'}}"
                                 on-mousedown="{{handleAttributeParseSelect}}" data-name="string">String
                            </div>
                            <div flex class="selitem" data-checked="{{attributeParse == 'list'}}"
                                 on-mousedown="{{handleAttributeParseSelect}}" data-name="list">List
                            </div>
                        </div>
                    </template>

                </div>
                <div vertical layout flex>

                    <label hidden?="{{attributeType != 'continuous'}}">Continous mapping</label>

                    <div hidden?="{{attributeType != 'continuous'}}">
                        <div class="button action" on-click="{{handleAddPoint}}" style="margin:0 3px 3px 0;width:150px;">Add point</div>
                        <div horizontal layout style="margin-bottom:1px;">
                            <label flex>Attribute value</label>
                            <label flex>Render value</label>
                            <label style="width: 60px;text-align: right">Gradient</label>
                        </div>
                        <div flex horizontal layout style="margin-bottom:5px;">
                            <div flex vertical layout>
                                <template repeat="{{point, index in points}}">
                                    <jso-attribute-render-color-point
                                            point="{{point}}" points="{{points}}" controlType="{{controlType}}"
                                            allowRemove="{{index != 0 && index != points.length -1}}">
                                    </jso-attribute-render-color-point>
                                </template>
                            </div>
                            <div style="margin-left:3px" id="colorLegend"></div>
                        </div>
                        <div class="button action" on-click="{{handleApplyInterpolation}}" style="margin-bottom:5px;width:150px;">Apply mapping</div>
                    </div>
                    <label>Assign render values to attributes</label>

                    <div>
                        <div class="table-head" horizontal layout>
                            <div flex>Attribute value</div>
                            <div flex>Render value</div>
                        </div>
                        <core-list id="list" data="{{uniqueData}}" height="27">
                            <template>
                                <div horizontal layout class="table-row">
                                    <div flex>{{model.attribute}}</div>
                                    <div tabindex="-1" class="colorbox" style="background-color:{{model.render}};"
                                         on-click="{{handleChangeFocusInUniqueColor}}"
                                         on-focusout="{{handleChangeFocusOutUniqueColor}}"
                                            ></div>
                                    <input flex type="text" value="{{model.render}}">
                                </div>
                            </template>
                        </core-list>
                    </div>


                    <div horizontal layout hidden?="{{attributeType != 'discrete'}}" style="margin-top:8px;">
                        <label>Edit default</label>
                        <!--<div class="button action">Select all</div>-->
                        <!--<div class="button action">Deselect all</div>-->
                        <!--<div class="text">Selection:</div>-->
                        <jso-color-picker flex color="{{defaultValue}}"></jso-color-picker>
                    </div>
                </div>
            </div>
            <div class="footer" horizontal layout end-justified>
                <div class="button action" on-click="{{handleApplyDirect}}">Use attribute value directly</div>
                <div class="button action" style="width: 100px;" on-click="{{handleOk}}">OK</div>
            </div>
            <jso-color-menu id="colormenu" hide="{{hideColorMenu}}" flex on-color-click="{{handleColorMenu}}"></jso-color-menu>
        </div>

    </template>
    <script>
        Polymer({
            created: function () {
                this.isReady = false;
                this.attributeName = '';
                this.attributeType = 'discrete';
                this.attributeParse = 'string';

                this.uniqueData = [];
                this.uniqueMatches = {};
                /**/
                this.hideColorMenu = true;
                this.lastUniqueModel;
            },
            ready: function () {
                var me = this;
                this.points = [
                    {value: 0, render: this.defaultValue},
                    {value: 0, render: this.defaultValue}
                ];
                this.handleApplyInterpolation();

                var observer = new MutationObserver(function (mutations) {
                    me.$.list.updateSize();
                }.bind(this));
                observer.observe(this, {attributes: true, attributeFilter: ['hidden']});
            },
            domReady: function () {
                this.isReady = true;
            },
            /** Color **/
            handleChangeFocusInUniqueColor: function (e) {
                this.lastUniqueModel = e.target.templateInstance.model.model;
                this.$.colormenu.style.top = (22 + e.currentTarget.getBoundingClientRect().top) + "px";
                this.$.colormenu.style.left = e.currentTarget.getBoundingClientRect().left + "px";
                this.hideColorMenu = !this.hideColorMenu;
            },
            handleChangeFocusOutUniqueColor: function (e) {
                this.hideColorMenu = true;
            },
            handleColorMenu: function (e) {
                this.lastUniqueModel.render = e.detail.color;
                this.hideColorMenu = true;
            },

            defaultValueChanged: function (oldValue, newValue) {
                for (var i = 0; i < this.uniqueData.length; i++) {
                    var data = this.uniqueData[i];
                    if (data.render === oldValue) {
                        data.render = newValue;
                    }
                }
            },
            visualSetChanged: function () {
                if (this.visualSet) {
                    this.attributeType = this.visualSet.type;
                    this.attributeName = this.visualSet.attribute;
                    this.attributeParse = this.visualSet.parse;
                    this.uniqueMatches = this.visualSet.matches;
                    this.points = this.visualSet.points;
                }
            },
            attributeNameChanged: function (oldValue, newValue) {
                this._updateUniqueValues();
            },
            attributeParseChanged: function (oldValue, newValue) {
                this._updateUniqueValues();
            },
            attributeTypeChanged: function (oldValue, newValue) {
            },
            /* Observers */
            observe: {
                'attributeManager.data': 'handleAttributeManagerChange'
            },
            handleAttributeManagerChange: function (oldValue, newValue) {
                this._updateUniqueValues();
                if (this.isReady && this.visualSet && this.visualSet.enabled) {
                    this._updateVisualSet();
                    this.fire('ok', {displayProperty: this.getAttribute("id")});
                }
            },
            handleClose: function () {
                this.displayProperty = null;
            },
            handleOk: function () {
                this._updateVisualSet();
                this.fire('ok', {displayProperty: this.getAttribute("id")});
                this.handleClose();
            },
            _updateVisualSet: function () {
                if (this.attributeName != '') {
                    var uniqueMatches = {};
                    for (var i = 0; i < this.uniqueData.length; i++) {
                        var data = this.uniqueData[i];
                        uniqueMatches[data.attribute] = data.render;
                    }
                    this.uniqueMatches = uniqueMatches;
                    this.visualSet = {
                        attribute: this.attributeName,
                        displayProperty: this.getAttribute("id"),
                        type: this.attributeType,
                        matches: this.uniqueMatches,
                        parse: this.attributeParse,
                        points: this.points,
                        enabled: true
                    }
                }
            },
            handleAttributeNameSelect: function (e) {
                this.attributeName = e.currentTarget.dataset.name;
            },
            handleAttributeTypeSelect: function (e) {
                this.attributeType = e.currentTarget.dataset.name;
            },
            handleAttributeParseSelect: function (e) {
                this.attributeParse = e.currentTarget.dataset.name;
            },
            handleAddPoint: function () {
                this.points.splice(this.points.length - 1, 0, {
                    value: 0, render: this.defaultValue
                });
            },
            handleApplyInterpolation: function () {
                this._updateUniqueInterpolatedValues();
            },

            _updateUniqueValues: function () {
                var me = this;
                if (this.attributeName != '') {
                    var uniqueMap = {};
                    var uniqueData = [];
                    var max = 0;
                    var min = 0;

                    var processValue = function (value) {
                        if (value) {
                            if (!uniqueMap[value]) {
                                uniqueMap[value] = true;
                                var render = me.defaultValue;
                                if (me.visualSet && me.visualSet.attribute == me.attributeName) {
                                    if (me.visualSet.matches[value] != null) {
                                        render = me.visualSet.matches[value];
                                    }
                                }
                                uniqueData.push({attribute: value, render: render});
                            }
                            var attribute = parseFloat(value);
                            if (attribute >= max) {
                                max = attribute;
                            }
                            if (attribute <= min) {
                                min = attribute;
                            }
                        }
                    };

                    var row, value;
                    if (this.attributeParse == "list") {
                        var splitStr = ",", values;
                        for (var i = 0, l = this.attributeManager.data.length; i < l; i++) {
                            row = this.attributeManager.data[i];
                            value = row[this.attributeName];
                            if (value == null) {
                                value = "";
                            }
                            values = value.split(splitStr);
                            for (var j = 0, lj = values.length; j < lj; j++) {
                                processValue(values[j]);
                            }
                        }
                    } else {
                        for (var i = 0, l = this.attributeManager.data.length; i < l; i++) {
                            row = this.attributeManager.data[i];
                            processValue(row[this.attributeName]);
                        }
                    }

                    if (this.points.length == 0) {
                        this.points.push({value: min, render: this.defaultValue});
                        this.points.push({value: max, render: this.defaultValue});
                    } else {
                        this.points[0].value = min;
                        this.points[this.points.length - 1].value = max;
                    }

                    uniqueData.sort(function (a, b) {
                        return parseFloat(a.attribute) - parseFloat(b.attribute);
                    });
                    this.uniqueData = uniqueData;
                    if (this.attributeType == 'continuous') {
                        this._updateUniqueInterpolatedValues();
                    }
                }
            },

            _updateUniqueInterpolatedValues: function () {
                this.points.sort(function (a, b) {
                    return parseFloat(a.value) - parseFloat(b.value);
                });

                var totalDiff = this.points[this.points.length - 1].value - this.points[0].value;
                var gradientValues = [this.points[0].render + " 0%"];
                var percent = 0;
                for (var i = 0, l = this.points.length - 1; i < l; i++) {
                    var point = this.points[i];
                    var nextPoint = this.points[i + 1];
                    if (nextPoint) {
                        percent += 100 * (nextPoint.value - point.value) / totalDiff;
                        gradientValues.push(nextPoint.render + " " + Math.round(percent) + "%");
                    }
                }
                this.$.colorLegend.style.background = "linear-gradient(to bottom, " + gradientValues.join(", ") + " )";

                for (var i = 0, l = this.uniqueData.length; i < l; i++) {
                    var value = parseFloat(this.uniqueData[i].attribute);
                    for (var j = 0; j < this.points.length; j++) {
                        var point = this.points[j];
                        var nextPoint = this.points[j + 1];
                        if (nextPoint) {
                            var pointValue = parseFloat(point.value);
                            var pointRender = point.render;
                            var nextPointValue = parseFloat(nextPoint.value);
                            var nextPointRender = nextPoint.render;
                            if (value >= pointValue && value <= nextPointValue) {
                                var interpolator = d3.interpolateRgb(pointRender, nextPointRender);
                                var normalizedValue = (value - pointValue) / (nextPointValue - pointValue);
                                if (isNaN(normalizedValue)) {
                                    normalizedValue = 0;
                                }
                                this.uniqueData[i].render = interpolator(normalizedValue);
                            }
                        }
                    }
                }
            },
            handleApplyDirect: function () {
                for (var i = 0; i < this.uniqueData.length; i++) {
                    var data = this.uniqueData[i];
                    data.render = data.attribute;
                }
            }
        });
    </script>
</polymer-element>

<polymer-element name="jso-attribute-render-color-point"
                 attributes="point points allowRemove">
    <template>
        <link rel="stylesheet" href="../../jso-style.css">
        <style>
            :host {
                display: block;
                position: relative;
                box-sizing: border-box;
                margin: 1px 0;
            }

            [horizontal] > * {
                margin-right: 3px;
            }

            [horizontal] > *:last-child {
                margin-right: 0px;
            }

            .text {
                width: 100px;
            }

            .remove::after {
                font-family: FontAwesome;
                content: '\f00d';
                color: #c70804;
            }

            .remove[allowRemove] {
                visibility: hidden
            }

            .remove[allowRemove=true] {
                visibility: inherit;
            }
        </style>
        <div horizontal layout>
            <input flex type="number" value="{{point.value}}">

            <!--<input flex type="color" value="{{point.render}}">-->
            <jso-color-picker flex color="{{point.render}}"></jso-color-picker>


            <div class="button action remove" allowRemove="{{allowRemove}}" on-click="{{handleRemove}}"></div>
        </div>
    </template>
    <script>
        Polymer({
            handleRemove: function () {
                this.points.splice(this.points.indexOf(this.point), 1);
            }
        });
    </script>
</polymer-element>