/**
 * Created by liangwensen on 3/14/16.
 */

import lang from 'zero-lang';
import htmlUtils from 'zero-text/html';
import domAttr from 'zero-dom/attr';
import domQuery from 'zero-dom/query';
import domStyle from 'zero-dom/style';
import instanceCache from './storage/instance';
import sprintf from 'zero-fmt/sprintf';
import tmplTopic from './template/topic';
import win from 'zero-lang/global';

const templateHelper = lang.extend({}, lang, htmlUtils);

let container = domQuery.one('#xmind-container');
let svg;
let inner;
let g;
let render;

function initGraph() {
    container.innerHTML = [
        '<svg id="canvas">',
            '<g/>',
        '</svg>',
    ].join('');
    svg = d3.select('svg');
    inner = svg.select('g');
    inner.innerHTML = '';
    render = new dagreD3.render();
    g = new dagreD3.graphlib.Graph().setGraph({
        nodesep: 10,
        ranksep: 30,
        rankdir: 'LR',
        marginx: 20,
        marginy: 20,
    });
}

//let isFirstRendered = true;
function afterRendered() {
    // zooming
    let zoom = d3.behavior.zoom().on('zoom', function () {
        inner.attr(
            'transform',
            sprintf('translate(%s)scale(%s)', d3.event.translate, d3.event.scale)
        );
    });

    svg.call(zoom);

    let zoomScale = zoom.scale();
    let graphWidth = g.graph().width + 80;
    let graphHeight = g.graph().height + 40;
    let width = parseInt(svg.style('width').replace(/px/, ''));
    let height = parseInt(svg.style('height').replace(/px/, ''));
    zoomScale = Math.min(width / graphWidth, height / graphHeight);
    let translate = [
        (width / 2) - ((graphWidth * zoomScale) / 2),
        (height / 2) - ((graphHeight * zoomScale) / 2),
    ];
    zoom.translate(translate);
    zoom.scale(zoomScale);
    zoom.event(svg);

    // adding uniqueId for nodes
    inner.selectAll('g.node')
        .attr('data-id', function (id) {
            return id;
        });
}

function processTopic(topic, parentTopic) {
    let hyperlinkType = '';
    let hyperlink = topic.hyperlink || '';
    if (hyperlink.match(/^file/)) {
        hyperlinkType = 'file';
    }

    if (hyperlink.match(/^http/)) {
        hyperlinkType = 'http';
    }

    if (hyperlink.match(/^xmind/)) {
        hyperlinkType = 'xmind';
    }

    return lang.extend({}, {
        hyperlinkType: hyperlinkType,
        styleId: '',
        classname: topic.isRootTopic ?
            'primary' :
            parentTopic && parentTopic.isRootTopic ?
                'secondary' :
                'normal',
    }, topic);
}

function setGraph(topic, parentTopic) {
    topic = processTopic(topic, parentTopic);
    g.setNode(topic.id, {
        class: topic.classname,
        labelType: 'html',
        label: tmplTopic(topic, templateHelper),
        rx: 5,
        ry: 5,
        padding: 0,
    });
    if (topic.children && topic.children.length) {
        lang.each(topic.children, function (child) {
            setGraph(child, topic);
            let lineAttrs = {
                label: '',

                //arrowhead: 'vee',
                lineInterpolate: 'basis',
            };
            if (child.type === 'detached') {
                lineAttrs.style = 'fill: none; stroke-dasharray: 5, 5;';
            }

            g.setEdge(topic.id, child.id, lineAttrs);
        });
    }
}

let currentSheetId;

let main = {
    render(sheetIndex) {
        let instance = instanceCache.get('current');
        if (instance) {
            sheetIndex = sheetIndex || 0;
            let sheet = instance.sheets[sheetIndex];
            sheet = sheet || instance.sheetById[sheetIndex];

            if (!sheet || sheet.id === currentSheetId) {
                return main;
            }

            initGraph();
            let rootTopic = sheet.rootTopic;

            setGraph(rootTopic.toPlainObject());

            // Run the renderer. This is what draws the final graph.
            render(inner, g);
            afterRendered();
            currentSheetId = sheet.id;
        }

        return main;
    },

    translate(x, y, scale, duration) {
        if (lang.isFinite(x) && lang.isFinite(y)) {
            let originScale = 1;
            let originScaleExpression = /scale\(([\d|\.]+)\)/.exec(
                inner.node().getAttribute('transform')
            );
            if (originScaleExpression) {
                originScale = originScaleExpression[1];
            }

            scale = scale || originScale;
            duration = duration || 200;
            inner.transition()
                .duration(duration)
                .attr(
                    'transform',
                    'translate(' + x + ', ' + y + ')scale(' + scale + ')'
                );
        }
    },

    unhighlightNodes() {
        inner.selectAll('g.node.highlight')
            .classed('highlight', false);
    },

    highlight(topicIds) {
        topicIds = topicIds || [];
        if (!lang.isArray(topicIds)) {
            topicIds = [topicIds];
        }

        main.unhighlightNodes();

        lang.each(topicIds, function (id) {
            inner.select(sprintf('[data-id="%s"]', id))
                .classed('highlight', true);
        });

        if (topicIds.length === 1) {
            let node = inner.select(sprintf('[data-id="%s"]', topicIds[0]));

            if (node) {
                let canvasHeight = domStyle.get(container, 'height');
                let canvasWidth = domStyle.get(container, 'width');
                let translateExpression = /translate\(([\d|\.]+),\s*([\d|\.]+)\)/.exec(
                    node.node().getAttribute('transform')
                );
                let canvasCenter = {
                    x: canvasWidth / 2,
                    y: canvasHeight / 2,
                };
                let nodeTranslate = {
                    x: 0,
                    y: 0,
                };

                if (translateExpression) {
                    nodeTranslate.x = parseInt(translateExpression[1], 10);
                    nodeTranslate.y = parseInt(translateExpression[2], 10);
                    main.translate(
                        (canvasCenter.x - nodeTranslate.x),
                        (canvasCenter.y - nodeTranslate.y)
                    );
                }
            } else {
                console.log('cannot find node: ', topicIds[0]);
            }
        }

        return main;
    },
};

export default main;
