var ctx = {
    applyFillColor: false,
    cellStyleApplying: false,
    updatingSelection: false,
    appliedClass: '',
    isFrozen: false,
    menuFormat: '',
    flexSheet: null,
    cboFontName: null,
    cboFontSize: null,
    boldBtn: null,
    italicBtn: null,
    underlineBtn: null,
    leftBtn: null,
    centerBtn: null,
    rightBtn: null,
    mergeBtn: null,
    frozenBtn: null,
    undoBtn: null,
    redoBtn: null,
    chartTypesBtn: null,
    lbChartTypes: null,
    undoStack: null,
    sortManager: null,
    columns: null,
    moveup: null,
    movedown: null,
    tbody: null,
    selectionFormatState: {},
    selection: {},
    chartEngine: null
};

c1.documentReady(function () {
    initInputs();
    initFlexSheet();
    initSort();
    updateSortTable();
    initChartEngine();
    document.body.addEventListener('keydown', function(e) {
        var lbChartTypes = ctx.lbChartTypes;
        if (lbChartTypes) {
            if (e.keyCode === 27) {
                lbChartTypes.hostElement.style.display = 'none';
            }
            if (e.keyCode === 13 && lbChartTypes.hostElement.style.display !== 'none') {
                addChart();
            }
        }

        hidePopup(e);
    });

    document.body.addEventListener('click', function (e) {
        var lbChartTypes = ctx.lbChartTypes;
        if (lbChartTypes) {
            lbChartTypes.hostElement.style.display = 'none';
        }

        hidePopup(e);
    }, true);
});

function initChartEngine() {
    ctx.chartEngine = new wijmo.grid.sheet.chart.ChartEngine(ctx.flexSheet);
    var lbChartTypes = ctx.lbChartTypes = wijmo.Control.getControl("#lbChartTypes");
    if (lbChartTypes) {
        lbChartTypes.hostElement.addEventListener('click', function() {
            addChart();
        });
    }
}

function addChart() {
    var lbChartTypes = ctx.lbChartTypes, chartType = null;
    if (lbChartTypes.selectedValue != null) {
        chartType = wijmo.asEnum(lbChartTypes.selectedValue, wijmo.chart.ChartType);
    }
    ctx.chartEngine.addChart(chartType);
    lbChartTypes.hostElement.style.display = 'none';
}

function initInputs() {
    ctx.cboFontName = wijmo.Control.getControl('#cboFontName');
    ctx.cboFontSize = wijmo.Control.getControl('#cboFontSize');
    initBtns();
    initColorPicker();
}

function initSort() {
    ctx.sortManager = ctx.flexSheet.sortManager;
    ctx.moveup = wijmo.getElement('#moveup');
    ctx.movedown = wijmo.getElement('#movedown');
    ctx.tbody = wijmo.getElement('#sortTable tbody');
    ctx.columns = getColumns();
    updateSortTable();
}

function initBtns() {
    ctx.boldBtn = wijmo.getElement('#boldBtn');
    ctx.italicBtn = wijmo.getElement('#italicBtn');
    ctx.underlineBtn = wijmo.getElement('#underlineBtn');
    ctx.leftBtn = wijmo.getElement('#leftBtn');
    ctx.centerBtn = wijmo.getElement('#centerBtn');
    ctx.rightBtn = wijmo.getElement('#rightBtn');
    ctx.frozenBtn = wijmo.getElement('#frozenBtn');
    ctx.mergeBtn = wijmo.getElement('#mergeBtn');
    ctx.undoBtn = wijmo.getElement('#undoBtn');
    ctx.redoBtn = wijmo.getElement('#redoBtn');
    ctx.chartTypesBtn = wijmo.getElement('#chartTypesBtn');
}

function updateBtns() {
    updateActiveState(ctx.selectionFormatState.isBold, ctx.boldBtn);
    updateActiveState(ctx.selectionFormatState.isItalic, ctx.italicBtn);
    updateActiveState(ctx.selectionFormatState.isUnderline, ctx.underlineBtn);
    updateActiveState(ctx.selectionFormatState.textAlign === 'left', ctx.leftBtn);
    updateActiveState(ctx.selectionFormatState.textAlign === 'center', ctx.centerBtn);
    updateActiveState(ctx.selectionFormatState.textAlign === 'right', ctx.rightBtn);
    ctx.mergeBtn.title = ctx.selectionFormatState.isMergedCell ? 'UnMerge' : 'Merge';
    ctx.frozenBtn.querySelector(".text").innerText = ctx.isFrozen ? 'UnFreeze' : 'Freeze';
    ctx.undoBtn.disabled = !ctx.flexSheet.undoStack.canUndo;
    ctx.redoBtn.disabled = !ctx.flexSheet.undoStack.canRedo;
}

function updateActiveState(condition, btn) {
    condition ? addClass(btn, "active") : removeClass(btn, "active");
}

function initFlexSheet() {
    var flexSheet;
    ctx.flexSheet = wijmo.Control.getControl('#excelLikeSheet');
    flexSheet = ctx.flexSheet;
    if (flexSheet) {
        ctx.undoStack = flexSheet.undoStack;

        flexSheet.selectedSheetChanged.addHandler(function (sender, args) {
            ctx.sortManager = flexSheet.sortManager;

            if (flexSheet.frozenColumns > 0 || flexSheet.frozenRows > 0) {
                ctx.isFrozen = true;
            } else {
                ctx.isFrozen = false;
            }

            updateSortTable();
            updateBtns();
        });

        flexSheet.undoStack.undoStackChanged.addHandler(function(sender, args) {
            updateBtns();
        });

        flexSheet.selectionChanged.addHandler(function (sender, args) {
            ctx.selectionFormatState = flexSheet.getSelectionFormatState();
        });

        flexSheet.columns.collectionChanged.addHandler(function () {
            ctx.columns = getColumns();
        });
        flexSheet.loaded.addHandler(function () {
            ctx.columns = getColumns();
        });

        if (ctx.sortManager) {
            ctx.sortManager = flexSheet.sortManager;
        }

        initSheetData();
    }
}

function initSheetData() {
    var s = ctx.flexSheet, i = 0;
    for (; i < s.sheets.length; i++) {
        s.sheets.selectedIndex = i;
        switch (s.sheets[i].name) {
            case 'Country':
                applyDataMap(s);
                break;
            case 'Report':
                generateUseCaseTemplateSheet(s);
                break;
            case 'Formulas':
                generateFormulasSheet(s);
                break;
        }
    }

    s.sheets.selectedIndex = 0;
}

function initColorPicker() {
    var colorPicker = ctx.colorPicker = wijmo.Control.getControl('#colorPicker'),
        ua = window.navigator.userAgent,
        blurEvt;

    if (colorPicker) {
        // if the browser is firefox, we should bind the blur event. (TFS #124387)
        // if the browser is IE, we should bind the focusout event. (TFS #124500)
        blurEvt = /firefox/i.test(ua) ? 'blur' : 'focusout';
        // Hide the color picker control when it lost the focus.
        colorPicker.hostElement.addEventListener(blurEvt, function () {
            setTimeout(function () {
                if (!colorPicker.containsFocus()) {
                    ctx.applyFillColor = false;
                    colorPicker.hostElement.style.display = 'none';
                }
            }, 0);
        });

        colorPicker.hostElement.addEventListener('keydown', function (e) {
            if (e.keyCode === 27) {
                colorPicker.hostElement.style.display = 'none';
            }
        });

        // Initialize the value changed event handler for the color picker control.
        colorPicker.valueChanged.addHandler(function () {
            if (ctx.applyFillColor) {
                ctx.flexSheet.applyCellsStyle({ backgroundColor: colorPicker.value });
            } else {
                ctx.flexSheet.applyCellsStyle({ color: colorPicker.value });
            }
        });
    }
}

function fontChanged(sender) {
    if (!ctx.updatingSelection && ctx.flexSheet) {
        ctx.flexSheet.applyCellsStyle({ fontFamily: ctx.cboFontName.selectedItem.Value });
    }
}

function fontSizeChanged(sender) {
    if (!ctx.updatingSelection && ctx.flexSheet) {
        ctx.flexSheet.applyCellsStyle({ fontSize: ctx.cboFontSize.selectedItem.Value });
    }
}

// apply style for the selected cells
function applyCellStyle(className, cancelCellStyle) {
    if (cancelCellStyle) {
        if (ctx.cellStyleApplying) {
            ctx.cellStyleApplying = false;
        } else {
            ctx.flexSheet.applyCellsStyle();
        }
    } else {
        if (className) {
            ctx.appliedClass = className + '-style';
            ctx.flexSheet.applyCellsStyle({ className: ctx.appliedClass }, undefined, true);
        } else if (ctx.appliedClass) {
            ctx.flexSheet.applyCellsStyle({ className: ctx.appliedClass });
            ctx.appliedClass = '';
            ctx.cellStyleApplying = true;
        }
    }
};

// apply the text alignment for the selected cells
function applyCellTextAlign(textAlign) {
    ctx.flexSheet.applyCellsStyle({ textAlign: textAlign });
    ctx.selectionFormatState.textAlign = textAlign;
    updateBtns();
};

// apply the bold font weight for the selected cells
function applyBoldStyle() {
    ctx.flexSheet.applyCellsStyle({ fontWeight: ctx.selectionFormatState.isBold ? 'none' : 'bold' });
    ctx.selectionFormatState.isBold = !ctx.selectionFormatState.isBold;
    updateBtns();
};

// apply the underline text decoration for the selected cells
function applyUnderlineStyle() {
    ctx.flexSheet.applyCellsStyle({ textDecoration: ctx.selectionFormatState.isUnderline ? 'none' : 'underline' });
    ctx.selectionFormatState.isUnderline = !ctx.selectionFormatState.isUnderline;
    updateBtns();
};

// apply the italic font style for the selected cells
function applyItalicStyle() {
    ctx.flexSheet.applyCellsStyle({ fontStyle: ctx.selectionFormatState.isItalic ? 'none' : 'italic' });
    ctx.selectionFormatState.isItalic = !ctx.selectionFormatState.isItalic;
    updateBtns();
};

// export 
function exportExcel() {
    ctx.flexSheet.save('FlexSheet.xlsx');
};

// import
function importExcel(element) {
    var flexSheet = ctx.flexSheet,
        grids = [],
        reader;

    if (flexSheet && element.files[0]) {
        flexSheet.load(element.files[0]);
        element.value = '';
    }
};

// New flexSheet
function newFile() {
    var flexSheet = ctx.flexSheet;
    if (flexSheet) {
        flexSheet.clear();
    }
};

function mergeCells() {
    var flexSheet = ctx.flexSheet;

    if (flexSheet) {
        flexSheet.mergeRange();
        ctx.selectionFormatState = flexSheet.getSelectionFormatState();
        updateBtns();
    }
}

function freeze() {
    var flexSheet = ctx.flexSheet;
    if (flexSheet) {
        flexSheet.freezeAtCursor();

        if (flexSheet.frozenColumns > 0 || flexSheet.frozenRows > 0) {
            ctx.isFrozen = true;
        } else {
            ctx.isFrozen = false;
        }
        updateBtns();
    }
}

// Excutes undo command.
function undo() {
    ctx.flexSheet.undo();
    updateBtns();
};

// Excutes redo command.
function redo() {
    ctx.flexSheet.redo();
    updateBtns();
};

function hidePopup(e) {
    var colorPicker = ctx.colorPicker,
        modals = document.querySelectorAll('.modal'),
        i;

    if (e.keyCode === 27) {
        if (modals && modals.length > 0) {
            for (i = 0; i < modals.length; i++) {
                $(modals[i]).modal('hide');
            }
        }
    }
}

// Show the column filter for the flexSheet control.
function showFilter() {
    ctx.flexSheet.showColumnFilter();
}

// show the color picker control.
function showColorPicker(e, isFillColor) {
    var colorPicker = ctx.colorPicker,
        offset = cumulativeOffset(e.target);

    if (colorPicker) {
        colorPicker.hostElement.style.display = 'inline';
        colorPicker.hostElement.style.left = offset.left + 'px';
        colorPicker.hostElement.style.top = (offset.top + e.target.clientHeight + 2) + 'px';
        colorPicker.hostElement.focus();
    }

    ctx.applyFillColor = isFillColor;
};

function applyDataMap(flexSheet) {
    var countries = ['US', 'Germany', 'UK', 'Japan', 'Italy', 'Greece'],
        products = ['Widget', 'Gadget', 'Doohickey'], column;
    // initialize the dataMap for the bound sheet.
    if (flexSheet) {
        column = flexSheet.columns.getColumn('Country');
        if (column && !column.dataMap) {
            column.dataMap = buildDataMap(countries);
        }
        column = flexSheet.columns.getColumn('Product');
        if (column && !column.dataMap) {
            column.dataMap = buildDataMap(products);
        }
    }
}

function buildDataMap(items) {
    var map = [];
    for (var i = 0; i < items.length; i++) {
        map.push({ key: i, value: items[i] });
    }
    return new wijmo.grid.DataMap(map, 'key', 'value');
}

// check font family for the font name combobox of the ribbon.
function checkFontfamily(fontFamily) {
    var fonts = ctx.cboFontName.itemsSource.items,
        fontIndex = 0,
        font;

    if (!fontFamily) {
        return fontIndex;
    }

    for (; fontIndex < fonts.length; fontIndex++) {
        font = fonts[fontIndex];

        if (font.Name === fontFamily || font.Value === fontFamily) {
            return fontIndex;
        }
    }

    return 0;
}

// check font size for the font size combobox of the ribbon.
function checkFontSize(fontSize) {
    var sizeList = ctx.cboFontSize.itemsSource.items,
        index = 0,
        size;

    if (fontSize == undefined) {
        return 5;
    }

    for (; index < sizeList.length; index++) {
        size = sizeList[index];

        if (size.Value === fontSize || size.Name === fontSize) {
            return index;
        }
    }

    return 5;
}

function showChartTypes() {
    var lbChartTypes = ctx.lbChartTypes,
        parent = ctx.chartTypesBtn.parentElement,
        offset = cumulativeOffset(parent);

    if (lbChartTypes) {
        lbChartTypes.selectedIndex = -1;
        lbChartTypes.hostElement.style.display = 'inline';
        lbChartTypes.hostElement.style.left = offset.left + 'px';
        lbChartTypes.hostElement.style.top = (offset.top + parent.clientHeight + 2) + 'px';
        lbChartTypes.hostElement.focus();
    }
}

// Get the absolute position of the dom element.
function cumulativeOffset(element) {
    var top = 0, left = 0;

    do {
        top += element.offsetTop || 0;
        left += element.offsetLeft || 0;
        element = element.offsetParent;
    } while (element);

    return {
        top: top,
        left: left
    };
}

function hasClass(obj, cls) {
    return obj && obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}

function addClass(obj, cls) {
    if (!this.hasClass(obj, cls)) obj.className += " " + cls;
}

function removeClass(obj, cls) {
    if (hasClass(obj, cls)) {
        var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
        obj.className = obj.className.replace(reg, ' ');
    }
}