/*
 * Copyright (C) 2015 Devin Rousso <dcrousso+webkit@gmail.com>. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

WebInspector.VisualStyleBackgroundPicker = class VisualStyleBackgroundPicker extends WebInspector.VisualStylePropertyEditor
{
    constructor(propertyNames, text, possibleValues, layoutReversed)
    {
        super(propertyNames, text, possibleValues, null, "background-picker", layoutReversed);

        this._gradientSwatch = new WebInspector.InlineSwatch(WebInspector.InlineSwatch.Type.Gradient);
        this._gradientSwatch.addEventListener(WebInspector.InlineSwatch.Event.ValueChanged, this._gradientSwatchColorChanged, this);
        this.contentElement.appendChild(this._gradientSwatch.element);

        this._valueInputElement = document.createElement("input");
        this._valueInputElement.classList.add("value-input");
        this._valueInputElement.type = "url";
        this._valueInputElement.placeholder = WebInspector.UIString("Enter a URL");
        this._valueInputElement.addEventListener("input", this._valueInputValueChanged.debounce(250, this));
        this.contentElement.appendChild(this._valueInputElement);

        this._valueTypePickerElement = document.createElement("select");
        this._valueTypePickerElement.classList.add("value-type-picker-select");
        if (this._possibleValues.advanced)
            this._valueTypePickerElement.title = WebInspector.UIString("Option-click to show all values");

        let imageOption = document.createElement("option");
        imageOption.value = "url";
        imageOption.text = WebInspector.UIString("Image");
        this._valueTypePickerElement.appendChild(imageOption);

        let linearGradientOption = document.createElement("option");
        linearGradientOption.value = "linear-gradient";
        linearGradientOption.text = WebInspector.UIString("Linear Gradient");
        this._valueTypePickerElement.appendChild(linearGradientOption);

        let radialGradientOption = document.createElement("option");
        radialGradientOption.value = "radial-gradient";
        radialGradientOption.text = WebInspector.UIString("Radial Gradient");
        this._valueTypePickerElement.appendChild(radialGradientOption);

        let repeatingLinearGradientOption = document.createElement("option");
        repeatingLinearGradientOption.value = "repeating-linear-gradient";
        repeatingLinearGradientOption.text = WebInspector.UIString("Repeating Linear Gradient");
        this._valueTypePickerElement.appendChild(repeatingLinearGradientOption);

        let repeatingRadialGradientOption = document.createElement("option");
        repeatingRadialGradientOption.value = "repeating-radial-gradient";
        repeatingRadialGradientOption.text = WebInspector.UIString("Repeating Radial Gradient");
        this._valueTypePickerElement.appendChild(repeatingRadialGradientOption);

        this._valueTypePickerElement.appendChild(document.createElement("hr"));

        this._createValueOptions(this._possibleValues.basic);
        this._advancedValuesElements = null;

        this._valueTypePickerElement.addEventListener("mousedown", this._keywordSelectMouseDown.bind(this));
        this._valueTypePickerElement.addEventListener("change", this._handleKeywordChanged.bind(this));
        this.contentElement.appendChild(this._valueTypePickerElement);

        this._currentType = "url";
    }

    // Public

    get value()
    {
        return this._valueInputElement.value;
    }

    set value(value)
    {
        if (!value || !value.length || value === this.value)
            return;

        const isKeyword = this.valueIsSupportedKeyword(value);
        this._currentType = isKeyword ? value : value.substring(0, value.indexOf("("));
        this._updateValueInput();
        if (!isKeyword)
            this._valueInputElement.value = value.substring(value.indexOf("(") + 1, value.length - 1);

        this._valueTypePickerElement.value = this._currentType;

        if (!this._currentType.includes("gradient"))
            return;

        this._updateGradient();
    }

    get synthesizedValue()
    {
        if (this.valueIsSupportedKeyword(this._currentType))
            return this._currentType;

        return this._currentType + "(" + this.value + ")";
    }

    // Protected

    parseValue(text)
    {
        const validPrefixes = ["url", "linear-gradient", "radial-gradient", "repeating-linear-gradient", "repeating-radial-gradient"];
        return validPrefixes.some((item) => text.startsWith(item)) ? [text, text] : null;
    }

    // Private

    _updateValueInput()
    {
        const supportedKeyword = this.valueIsSupportedKeyword(this._currentType);
        const gradientValue = this._currentType.includes("gradient");
        this.contentElement.classList.toggle("gradient-value", !supportedKeyword && gradientValue);
        this._valueInputElement.disabled = supportedKeyword;
        if (supportedKeyword) {
            this._valueInputElement.value = "";
            this._valueInputElement.placeholder = WebInspector.UIString("Using Keyword Value");
        } else {
            if (this._currentType === "image") {
                this._valueInputElement.type = "url";
                this._valueInputElement.placeholder = WebInspector.UIString("Enter a URL");
            } else if (gradientValue) {
                this._valueInputElement.type = "text";
                this._valueInputElement.placeholder = WebInspector.UIString("Enter a Gradient");
            }
        }
    }

    _updateGradient()
    {
        const value = this.synthesizedValue;
        if (!value || value === this._currentType)
            return;

        this._gradientSwatch.value = WebInspector.Gradient.fromString(value);
    }

    _gradientSwatchColorChanged(event)
    {
        this.value = event.data.value.toString();
        this._valueDidChange();
    }

    _valueInputValueChanged(event)
    {
        this._updateGradient();
        this._valueDidChange();
    }

    _keywordSelectMouseDown(event)
    {
        if (event.altKey)
            this._addAdvancedValues();
        else if (!this._valueIsSupportedAdvancedKeyword(this.value))
            this._removeAdvancedValues();
    }

    _handleKeywordChanged(event)
    {
        this._currentType = this._valueTypePickerElement.value;
        this._updateValueInput();
        this._updateGradient();
        this._valueDidChange();
    }

    _createValueOptions(values)
    {
        let addedElements = [];
        for (let key in values) {
            let option = document.createElement("option");
            option.value = key;
            option.text = values[key];
            this._valueTypePickerElement.appendChild(option);
            addedElements.push(option);
        }
        return addedElements;
    }

    _addAdvancedValues()
    {
        if (this._advancedValuesElements)
            return;

        this._valueTypePickerElement.appendChild(document.createElement("hr"));
        this._advancedValuesElements = this._createValueOptions(this._possibleValues.advanced);
    }

    _removeAdvancedValues()
    {
        if (!this._advancedValuesElements)
            return;

        this._valueTypePickerElement.removeChild(this._advancedValuesElements[0].previousSibling);
        for (let element of this._advancedValuesElements)
            this._valueTypePickerElement.removeChild(element);

        this._advancedValuesElements = null;
    }

    _toggleTabbingOfSelectableElements(disabled)
    {
        let tabIndex = disabled ? "-1" : null;
        this._valueInputElement.tabIndex = tabIndex;
        this._valueTypePickerElement.tabIndex = tabIndex;
    }
};
