import Node from './node';
import { defined, isTransparent } from '../util';
import { DASH_ARRAYS, SOLID, BUTT } from '../core/constants';
import { NONE } from './constants';
import renderAllAttr from './utils/render-all-attributes';
import renderAttr from './utils/render-attribute';
import NODE_MAP from './node-map';

var ATTRIBUTE_MAP = {
    "fill.opacity": "fill-opacity",
    "stroke.color": "stroke",
    "stroke.width": "stroke-width",
    "stroke.opacity": "stroke-opacity"
};
var SPACE = " ";

var PathNode = (function (Node) {
    function PathNode () {
        Node.apply(this, arguments);
    }

    if ( Node ) PathNode.__proto__ = Node;
    PathNode.prototype = Object.create( Node && Node.prototype );
    PathNode.prototype.constructor = PathNode;

    PathNode.prototype.geometryChange = function geometryChange () {
        this.attr("d", this.renderData());
        this.invalidate();
    };

    PathNode.prototype.optionsChange = function optionsChange (e) {
        switch (e.field) {
            case "fill":
                if (e.value) {
                    this.allAttr(this.mapFill(e.value));
                } else {
                    this.removeAttr("fill");
                }
                break;

            case "fill.color":
                this.allAttr(this.mapFill({ color: e.value }));
                break;

            case "stroke":
                if (e.value) {
                    this.allAttr(this.mapStroke(e.value));
                } else {
                    this.removeAttr("stroke");
                }
                break;

            case "transform":
                this.transformChange(e.value);
                break;

            default:
                var name = ATTRIBUTE_MAP[e.field];
                if (name) {
                    this.attr(name, e.value);
                }
                break;
        }

        Node.prototype.optionsChange.call(this, e);
    };

    PathNode.prototype.content = function content () {
        if (this.element) {
            this.element.textContent = this.srcElement.content();
        }
    };

    PathNode.prototype.renderData = function renderData () {
        return this.printPath(this.srcElement);
    };

    PathNode.prototype.printPath = function printPath (path) {
        var this$1 = this;

        var segments = path.segments;
        var length = segments.length;
        if (length > 0) {
            var parts = [];
            var output, currentType;

            for (var i = 1; i < length; i++) {
                var segmentType = this$1.segmentType(segments[i - 1], segments[i]);
                if (segmentType !== currentType) {
                    currentType = segmentType;
                    parts.push(segmentType);
                }

                if (segmentType === "L") {
                    parts.push(this$1.printPoints(segments[i].anchor()));
                } else {
                    parts.push(this$1.printPoints(segments[i - 1].controlOut(), segments[i].controlIn(), segments[i].anchor()));
                }
            }

            output = "M" + this.printPoints(segments[0].anchor()) + SPACE + parts.join(SPACE);
            if (path.options.closed) {
                output += "Z";
            }

            return output;
        }
    };

    PathNode.prototype.printPoints = function printPoints () {
        var points = arguments;
        var length = points.length;
        var result = [];

        for (var i = 0; i < length; i++) {
            result.push(points[i].toString(3));
        }

        return result.join(" ");
    };

    PathNode.prototype.segmentType = function segmentType (segmentStart, segmentEnd) {
        return segmentStart.controlOut() && segmentEnd.controlIn() ? "C" : "L";
    };

    PathNode.prototype.mapStroke = function mapStroke (stroke) {
        var attrs = [];

        if (stroke && !isTransparent(stroke.color)) {
            attrs.push([ "stroke", stroke.color ]);
            attrs.push([ "stroke-width", stroke.width ]);
            attrs.push([ "stroke-linecap", this.renderLinecap(stroke) ]);
            attrs.push([ "stroke-linejoin", stroke.lineJoin ]);

            if (defined(stroke.opacity)) {
                attrs.push([ "stroke-opacity", stroke.opacity ]);
            }

            if (defined(stroke.dashType)) {
                attrs.push([ "stroke-dasharray", this.renderDashType(stroke) ]);
            }
        } else {
            attrs.push([ "stroke", NONE ]);
        }

        return attrs;
    };

    PathNode.prototype.renderStroke = function renderStroke () {
        return renderAllAttr(
            this.mapStroke(this.srcElement.options.stroke)
        );
    };

    PathNode.prototype.renderDashType = function renderDashType (stroke) {
        var dashType = stroke.dashType;
        var width = stroke.width; if ( width === void 0 ) width = 1;

        if (dashType && dashType !== SOLID) {
            var dashArray = DASH_ARRAYS[dashType.toLowerCase()];
            var result = [];

            for (var i = 0; i < dashArray.length; i++) {
                result.push(dashArray[i] * width);
            }

            return result.join(" ");
        }
    };

    PathNode.prototype.renderLinecap = function renderLinecap (stroke) {
        var dashType = stroke.dashType;
        var lineCap = stroke.lineCap;

        return (dashType && dashType !== "solid") ? BUTT : lineCap;
    };

    PathNode.prototype.mapFill = function mapFill (fill) {
        var attrs = [];
        if (!(fill && fill.nodeType === "Gradient")) {
            if (fill && !isTransparent(fill.color)) {
                attrs.push([ "fill", fill.color ]);

                if (defined(fill.opacity)) {
                    attrs.push([ "fill-opacity", fill.opacity ]);
                }
            } else {
                attrs.push([ "fill", NONE ]);
            }
        }

        return attrs;
    };

    PathNode.prototype.renderFill = function renderFill () {
        return renderAllAttr(
            this.mapFill(this.srcElement.options.fill)
        );
    };

    PathNode.prototype.template = function template () {
        return "<path " + (this.renderId()) + " " + (this.renderStyle()) + " " + (this.renderOpacity()) + " " + (renderAttr('d', this.renderData())) +
                    "" + (this.renderStroke()) + (this.renderFill()) + (this.renderDefinitions()) + (this.renderTransform()) + "></path>";
    };

    return PathNode;
}(Node));

NODE_MAP.Path = PathNode;

export default PathNode;