define([
    'lib/stapes',
    'lib/tinycolor',
    'utils/Tools',
    'views/Slider'
], function (Stapes, Tinycolor, tools, Slider) {
    'use strict';
    var timer;

    function showMessageField (text, type) {
        var dom, wrapper;

        dom = document.querySelector('.work .msg');

        if (!dom) {
            dom = document.createElement('div');
            dom.classList.add('msg');
            dom.classList.add(type);
            wrapper = document.createElement('div');
            wrapper.classList.add('wrapper_msg');
            wrapper.classList.add('invisible');
            wrapper.appendChild(dom);

            document.querySelector('.work').appendChild(wrapper);
            setTimeout(function () {
                wrapper.classList.remove('invisible');
            }, 0);
        }

        if (!dom.classList.contains(type)) {
            dom.className = 'msg';
            dom.classList.add(type);
        }
        dom.innerHTML = text;
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(function () {
            var error = document.querySelector('.work .wrapper_msg');
            if (error) {
                error.parentNode.removeChild(error);
            }
        }, 1600);
    }

    return Stapes.subclass(/** @lends MainView.prototype*/{
        pointer: null,
        colorpicker: null,
        slider: null,
        sliderinput: null,
        cpradius: 0,
        cpcenter: 0,
        drag: false,
        color: null,
        brightness: 1.0,
        inputbox: null,

        /**
         * @class MainView
         * @construct
         * @fires barClick
         * @fires colorChange
         */
        constructor: function () {
            var ev;
            this.pointer = document.querySelector('#colorpicker #pointer');
            this.colorpicker = document.querySelector('#colorpicker #colorwheelbg');
            this.slider = new Slider({
                element: document.getElementById('brightness'),
                min: 0,
                max: 1,
                step: 0.02,
                value: 1
            });
            this.inputbox = document.querySelector('#color input.value');

            this.cpradius = this.colorpicker.offsetWidth / 2;
            this.cpcenter = this.colorpicker.offsetLeft + this.cpradius;

            this.bindEventHandlers();

            ev = document.createEvent('Event');
            ev.initEvent('resize', true, true);
            window.dispatchEvent(ev);
        },

        /**
         * @private
         */
        bindEventHandlers: function () {
            var cptouchrect;

            window.addEventListener('resize', function () {
                var attrW, attrH, side, w = this.colorpicker.parentNode.clientWidth, h = this.colorpicker.parentNode.clientHeight;

                attrW = this.colorpicker.getAttribute('width');
                attrH = this.colorpicker.getAttribute('height');
                side = attrW === 'auto' ? attrH : attrW;
                if (w > h) {
                    if (attrH !== side) {
                        this.colorpicker.setAttribute('height', side);
                        this.colorpicker.setAttribute('width', 'auto');
                    }
                } else if (attrW !== side) {
                    this.colorpicker.setAttribute('height', 'auto');
                    this.colorpicker.setAttribute('width', side);
                }

                this.cpradius = this.colorpicker.offsetWidth / 2;
                this.cpcenter = this.colorpicker.offsetLeft + this.cpradius;
                if (this.color) {
                    this.updatePointer();
                }
            }.bind(this));

            window.addClickHandler(document.querySelector('.footer'), function (event) {
                this.emit('barClick', event.target.parentNode.dataset.area);
            }.bind(this));


            this.slider.on('changeValue', function (value) {
                this.brightness = value.value;
                this.updateInput();
                this.fireColorEvent();
            }, this);

            this.inputbox.addEventListener('input', function (event) {
                var bright, rgb = new Tinycolor(event.target.value).toRgb();

                if (rgb.r === 0 && rgb.g === 0 && rgb.b === 0) {
                    this.brightness = 0;
                    this.color = new Tinycolor({
                        r: 0xff,
                        g: 0xff,
                        b: 0xff
                    });
                } else {
                    bright = Math.max(rgb.r, rgb.g, rgb.b) / 256;
                    rgb.r = Math.round(rgb.r / bright);
                    rgb.g = Math.round(rgb.g / bright);
                    rgb.b = Math.round(rgb.b / bright);
                    this.brightness = bright;
                    this.color = new Tinycolor(rgb);
                }

                this.fireColorEvent();
                this.updatePointer();
                this.updateSlider();
            }.bind(this), false);

            this.inputbox.addEventListener('keydown', function (event) {
                switch (event.keyCode) {
                    case 8:
                    case 9:
                    case 16:
                    case 37:
                    case 38:
                    case 39:
                    case 40:
                    case 46:
                        break;
                    default:
                    {
                        if (event.target.value.length >= 6 && (event.target.selectionEnd - event.target.selectionStart) === 0) {
                            event.preventDefault();
                            event.stopPropagation();
                        } else if (event.keyCode < 48 || event.keyCode > 71) {
                            event.preventDefault();
                            event.stopPropagation();
                        }
                    }
                }
            });

            cptouchrect = document.querySelector('#colorpicker .touchrect');
            window.addPointerDownHandler(cptouchrect, function (event) {
                this.leaveInput();
                this.drag = true;
                this.handleEvent(event);
            }.bind(this));

            window.addPointerMoveHandler(cptouchrect, function (event) {
                if (this.drag) {
                    this.handleEvent(event);
                    event.preventDefault();
                }
            }.bind(this));

            window.addPointerUpHandler(cptouchrect, function () {
                this.drag = false;
            }.bind(this));

            window.addClickHandler(document.querySelector('#clear_button'), function () {
                this.emit('clear');
            }.bind(this));

            window.addClickHandler(document.querySelector('#clearall_button'), function () {
                this.emit('clearall');
            }.bind(this));
        },

        /**
         * @private
         * @param event
         */
        handleEvent: function (event) {
            var point, x, y;

            if (event.touches) {
                x = event.touches[0].clientX;
                y = event.touches[0].clientY;
            } else {
                x = event.clientX;
                y = event.clientY;
            }
            point = this.getCirclePoint(x, y);
            this.color = this.getColorFromPoint(point);

            this.updatePointer();
            this.updateSlider();
            this.updateInput();

            this.fireColorEvent();
        },

        /**
         * @private
         * @param {number} x
         * @param {number} y
         * @returns {{x: number, y: number}}
         */
        getCirclePoint: function (x, y) {
            var p = {
                x: x,
                y: y
            }, c = {
                x: this.colorpicker.offsetLeft + this.cpradius,
                y: this.colorpicker.offsetTop + this.cpradius
            }, n;

            n = Math.sqrt(Math.pow((x - c.x), 2) + Math.pow((y - c.y), 2));

            if (n > this.cpradius) {
                p.x = (c.x) + this.cpradius * ((x - c.x) / n);
                p.y = (c.y) + this.cpradius * ((y - c.y) / n);
            }

            return p;
        },

        /**
         * @private
         * @param {{x: number, y: number}} p
         * @returns {Tinycolor}
         */
        getColorFromPoint: function (p) {
            var h, t, s, x, y;
            x = p.x - this.colorpicker.offsetLeft - this.cpradius;
            y = this.cpradius - p.y + this.colorpicker.offsetTop;
            t = Math.atan2(y, x);
            h = (t * (180 / Math.PI) + 360) % 360;
            s = Math.min(Math.sqrt(x * x + y * y) / this.cpradius, 1);

            return new Tinycolor({
                h: h,
                s: s,
                v: 1
            });
        },

        /**
         * @private
         * @param color
         * @returns {{x: number, y: number}}
         */
        getPointFromColor: function (color) {
            var t, x, y, p = {};

            t = color.h * (Math.PI / 180);
            y = Math.sin(t) * this.cpradius * color.s;
            x = Math.cos(t) * this.cpradius * color.s;

            p.x = Math.round(x + this.colorpicker.offsetLeft + this.cpradius);
            p.y = Math.round(this.cpradius - y + this.colorpicker.offsetTop);

            return p;
        },

        /**
         * @private
         */
        fireColorEvent: function () {
            var rgb = this.color.toRgb();
            rgb.r = Math.round(rgb.r * this.brightness);
            rgb.g = Math.round(rgb.g * this.brightness);
            rgb.b = Math.round(rgb.b * this.brightness);
            this.emit('colorChange', rgb);
        },

        /**
         *
         * @param rgb
         */
        setColor: function (rgb) {
            var bright;

            if (rgb.r === 0 && rgb.g === 0 && rgb.b === 0) {
                this.brightness = 0;
                this.color = new Tinycolor({
                    r: 0xff,
                    g: 0xff,
                    b: 0xff
                });
            } else {
                bright = Math.max(rgb.r, rgb.g, rgb.b) / 256;
                rgb.r = Math.round(rgb.r / bright);
                rgb.g = Math.round(rgb.g / bright);
                rgb.b = Math.round(rgb.b / bright);
                this.brightness = bright;
                this.color = new Tinycolor(rgb);
            }

            this.updatePointer();
            this.updateSlider();
            this.updateInput();
        },

        /**
         * @private
         */
        updateSlider: function () {
            this.slider.setValue(this.brightness);
            this.slider.dom.style.backgroundImage = '-webkit-linear-gradient(left, #000000 0%, ' + this.color.toHexString() + ' 100%)';
        },

        /**
         * @private
         */
        updatePointer: function () {
            var point = this.getPointFromColor(this.color.toHsv());

            this.pointer.style.left = (point.x - this.pointer.offsetWidth / 2) + 'px';
            this.pointer.style.top = (point.y - this.pointer.offsetHeight / 2) + 'px';
            this.pointer.style.backgroundColor = this.color.toHexString();
        },

        /**
         * @private
         */
        updateInput: function () {
            var rgb = this.color.toRgb();
            rgb.r = Math.round(rgb.r * this.brightness);
            rgb.g = Math.round(rgb.g * this.brightness);
            rgb.b = Math.round(rgb.b * this.brightness);

            this.inputbox.value = tools.b2hexstr(rgb.r) + tools.b2hexstr(rgb.g) + tools.b2hexstr(rgb.b);
        },

        /**
         * Scroll to the specific tab content
         * @param {string} id - Id of the tab to scroll to
         */
        scrollToArea: function (id) {
            var area, index;
            document.querySelector('.footer .selected').classList.remove('selected');
            document.querySelector('.footer .button[data-area =' + id + ']').classList.add('selected');

            area = document.getElementById(id);
            index = area.offsetLeft / area.clientWidth;
            area.parentNode.style.left = (-index * 100) + '%';
        },

        /**
         * Shows a status message
         * @param {string} message - Text to show
         */
        showStatus: function (message) {
            showMessageField(message, 'status');
        },

        /**
         * Shows the error text
         * @param {string} error - Error message
         */
        showError: function (error) {
            showMessageField(error, 'error');
        },

        /**
         * @private
         */
        leaveInput: function () {
            this.inputbox.blur();
        }
    });
});
