/**
 * Process kanban data
 * @param {string} key          Kanban key, used as kanban id
 * @param {Object} programGroup Group data
 * @returns {Object} kanban data
 */
function processKanbanData(key, programGroup)
{
    var kanbanId = key;

    /* Generate columns */
    var columns = [];
    var executionsCol;
    $.each(kanbanColumns, function(_, column)
    {
        var colType = column.type;
        column = $.extend({}, column,
        {
            kanban:     kanbanId,
            id:         kanbanId + '-' + column.type,
            parentType: (colType === 'doingProject' || colType === 'doingExecution') ? 'doing' : false,
        });

        if(colType === 'doingProject')
        {
            columns.push(
            {
                kanban:   kanbanId,
                id:       kanbanId + '-doing',
                type:     'doing',
                asParent: true,
                name:     doingText,
                count:    ''
            });
        }
        else if(colType === 'doingExecution')
        {
            executionsCol = column;
            executionsCol.count = 0;
        }

        columns.push(column);
    });
    /* Format lanes data */
    var lanes = [];
    $.each(programGroup, function(programId, statusMap)
    {
        var programName = programPairs[programId];
        var items       = {doingExecution: []};

        /* Projects and executions */
        ['wait', 'doing', 'closed'].forEach(function(status)
        {
            var itemsList = [];
            var statusProjects = statusMap[status];
            if(statusProjects)
            {
                $.each(statusProjects, function(_, project)
                {
                    var projectID = project.id;
                    var projectItem = $.extend({}, project, {id: 'project-' + projectID, _id: projectID});
                    itemsList.push(projectItem);

                    if(status === 'doing')
                    {
                        var execution = latestExecutions[projectID];
                        if(execution && execution.id)
                        {
                            executionsCol.count++;
                            projectItem.execution = $.extend({}, execution, {id: 'execution-' + execution.id, _id: execution.id});
                        }
                    }
                });
            }
            items[status + 'Project'] = itemsList;
        });

        lanes.push({id: programId, kanban: kanbanId, name: programName, items: items});
    });

    return {id: kanbanId, columns: columns, lanes: lanes};
}

/** Define kanban d-n-d rules */
var projectDropRules =
{
    waitProject:   ['doingProject', 'closedProject'],
    doingProject:  ['closedProject'],
    closedProject: ['doingProject'],
};
window.kanbanDropRules = {my: projectDropRules, other: projectDropRules};

/*
 * Find drop columns
 * @param {JQuery} $element Drag element
 * @param {JQuery} $root Dnd root element
 */
function findDropColumns($element, $root)
{
    var $col        = $element.closest('.kanban-col');
    var col         = $col.data();
    var lane        = $col.closest('.kanban-lane').data();
    var kanbanID    = $root.data('id');
    var kanbanRules = window.kanbanDropRules ? window.kanbanDropRules[kanbanID] : null;

    if(!kanbanRules) return $root.find('.kanban-lane[data-id="' + lane.id + '"] .kanban-lane-col:not([data-type="doingExecution"],[data-type="' + col.type + '"])');

    var colRules = kanbanRules[col.type];
    var lane     = $col.closest('.kanban-lane').data('lane');
    return $root.find('.kanban-lane-col').filter(function()
    {
        if(!colRules) return false;
        if(colRules === true) return true;

        var $newCol = $(this);
        var newCol = $newCol.data();
        if(newCol.id === col.id) return false;

        var $newLane = $newCol.closest('.kanban-lane');
        var newLane = $newLane.data('lane');
        return colRules.indexOf(newCol.type) > -1 && newLane.id === lane.id;
    });
}

/**
 * Change column type for a card
 * @param {Object} card        Card object
 * @param {String} fromColType The column type before change
 * @param {String} toColType   The column type after change
 * @param {String} kanbanID    Kanban ID
 */
function changeCardColType(card, fromColType, toColType, kanbanID)
{
    if(typeof card == 'undefined') return false;
    var cardID     = card.id;
    var projectID  = cardID.substr(cardID.indexOf("-") + 1);;
    var showIframe = false;

    if(toColType == 'doingProject')
    {
        if(fromColType == 'waitProject' && priv.canStart)
        {
            var link   = createLink('project', 'start', 'project=' + projectID, '', true);
            showIframe = true;
        }
        if(fromColType == 'closedProject' && priv.canActivate)
        {
            var link = createLink('project', 'activate', 'projectID=' + projectID, '', true);
            showIframe = true;
        }
    }
    else if(toColType == 'closedProject')
    {
        if(priv.canClose)
        {
            var link = createLink('project', 'close', 'projectID=' + projectID, '', true);
            showIframe = true;
        }
    }

    if(showIframe)
    {
        var modalTrigger = new $.zui.ModalTrigger({type: 'iframe', width: '80%', url: link});
        modalTrigger.show();
    }
}

/**
 * Handle finish drop task
 * @param {Object} event Event object
 * @returns {void}
 */
function handleFinishDrop(event)
{
    var $card    = $(event.element).closest('.kanban-item'); // The drag card
    var $dragCol = $card.closest('.kanban-lane-col');
    var $dropCol = $(event.target);

    /* Get d-n-d(drag and drop) infos. */
    var card        = $card.data('item');
    var fromColType = $dragCol.data('type');
    var toColType   = $dropCol.data('type');
    var kanbanID    = $card.closest('.kanban').data('id');

    changeCardColType(card, fromColType, toColType, kanbanID);
}

/** Calculate column height */
function calcColHeight(col, lane, colCards, colHeight)
{
    if (col.type !== 'doingProject') return colHeight;
    return colCards.length * 62;
}

$(function()
{
    /* Init all kanbans */
    $.each(kanbanGroup, function(key, programGroup)
    {
        var $kanban = $('#kanban-' + key);
        if(!$kanban.length) return;
        $kanban.kanban(
        {
            data:            processKanbanData(key, programGroup),
            calcColHeight:   calcColHeight,
            virtualize:      true,
            virtualCardList: true,
            droppable:
            {
                selector:     '.kanban-card:not(.execution-item)',
                target:       findDropColumns,
                finish:       handleFinishDrop
            },
        });
    });
});
