;(function (trv, $, window, document, undefined) {
    "use strict";
    
    var utils = trv.utils;
    if (!utils) {
        throw 'Missing telerikReporting.utils';
    }

    var stateFlags = {
        ExportInProgress: (1 << 0),
        PrintInProgress: (1 << 1)
    };
    
    function toolsModel(options) {
        var controller = options.controller;
        if (!controller) {
            throw "No options.controller.";
        }

        var historyManager = options.history;
        if (!historyManager) {
            throw "No options.history.";
        }
        
        function getDocumentMapVisible() {
            var args = {};
            controller.getDocumentMapVisible(args);
            return Boolean(args.visible);
        }

        function getParameterAreaVisible() {
            var args = {};
            controller.getParameterAreaVisible(args);
            return Boolean(args.visible);
        }
        
        return {
            'historyBack': new command(function () { historyManager.back(); }),

            'historyForward': new command(function () { historyManager.forward(); }),

            'goToPrevPage': new command(function () {
                controller.navigateToPage(controller.currentPageNumber() - 1);
            }),

            'goToNextPage': new command(function () {
                controller.navigateToPage(controller.currentPageNumber() + 1);
            }),

            'goToFirstPage': new command(function () {
                controller.navigateToPage(1);
            }),

            'goToLastPage': new command(function () {
                controller.navigateToPage(controller.pageCount());
            }),

            'goToPage': new command(function () { alert('goToPage'); }),

            'refresh': new command(function () {
                controller.refreshReport(true);
            }),

            'export': new command(function (format) {
                if (format) {
                    controller.exportReport(format);
                }
            }),

            'print': new command(function () {
                controller.printReport();
            }),

            'togglePrintPreview': new command(function () {

                controller.viewMode(
                    controller.viewMode() == trv.ViewMode.PrintPreview ?
                    trv.ViewMode.Interactive :
                    trv.ViewMode.PrintPreview
                );

            }),

            'toggleDocumentMap': new command(function () {
                controller.setDocumentMapVisible({ visible: !getDocumentMapVisible() });
            }),

            'toggleParametersArea': new command(function () {
                controller.setParameterAreaVisible({ visible: !getParameterAreaVisible() });
            }),
            
            'zoom': new command(function(scale) {
                controller.scale({ scale: 1 });
            }),
            
            'zoomIn': new command(function () {
                var args = {};
                controller.getScale(args);
                args.scale += getZoomStep(args.scale);
                controller.scale(args);
            }),
            
            'zoomOut': new command(function() {
                var args = {};
                controller.getScale(args);
                args.scale -= getZoomStep(args.scale);
                controller.scale(args);
            }),
            
            'toggleSideMenu': new command(function() {
                $(controller).trigger('toggleSideMenu');
            })
        };
    }
    
    function getZoomStep(scale) {
        if (scale < 1) {
            return 0.1;
        }
        return 0.5;
    }
    
    function toolsController(options) {

        function getState(flags) {
            return ((state & flags) != 0);
        }

        function setState(flags, value) {
            if (value) {
                state |= flags;
            }
            else {
                state &= ~flags;
            }
        }

        var controller = options.controller,
            historyManager = options.history,
            state = 0,
            refreshUI,
            model = options.model,
            $model = $(model)
        ;

        if (!controller) {
            throw "No controller (telerikReporting.ReportViewerController) has been specified.";
        }
        
        var modelChangeGuard;
        
        $model.bind("pageNumber", function (e, pageNumber) {
            if (!modelChangeGuard)
                controller.navigateToPage(pageNumber);
        });

        function getDocumentMapVisible() {
            var args = {};
            controller.getDocumentMapVisible(args);
            return Boolean(args.visible);
        }

        function getParameterAreaVisible() {
            var args = {};
            controller.getParameterAreaVisible(args);
            return Boolean(args.visible);
        }
        
        function updateUI() {
            if (!refreshUI) {
                refreshUI = true;
                window.setTimeout(function () {
                    try {
                        updateUICore();
                    } finally {
                        refreshUI = false;
                    }
                }, 10);
            }
        }

        function updateUICore() {

            var rs = controller.reportSource();
            var pageCount = controller.pageCount();
            var currentPageNumber = controller.currentPageNumber();

            var hasReport = (rs && rs.report);
            var hasPages = hasReport && pageCount > 0;

            var nextPage = hasPages && currentPageNumber < pageCount;
            var prevPage = hasPages && currentPageNumber > 1;

            var hasPage = hasPages && currentPageNumber;

            var hasDocumentMap = hasReport /* && ... has doc map */;
            var hasParametersArea = hasReport /* && ... has visible parameters */;

            model.goToFirstPage.enabled(prevPage);
            model.goToPrevPage.enabled(prevPage);

            model.goToLastPage.enabled(nextPage);
            model.goToNextPage.enabled(nextPage);

            model.goToPage.enabled(hasPages);

            model.print.enabled(hasReport && !getState(stateFlags.PrintInProgress));

            model.export.enabled(hasReport && !getState(stateFlags.ExportInProgress));

            model.refresh.enabled(hasReport);

            model.historyBack.enabled(historyManager && historyManager.canMoveBack());

            model.historyForward.enabled(historyManager && historyManager.canMoveForward());

            model.toggleDocumentMap
                .enabled(hasDocumentMap)
                .checked(getDocumentMapVisible());

            model.toggleParametersArea
                .enabled(hasParametersArea)
                .checked(getParameterAreaVisible());

            model.togglePrintPreview
                .enabled(hasReport)
                .checked(controller.viewMode() == trv.ViewMode.PrintPreview);

            model.zoom.enabled(hasPage);
            model.zoomIn.enabled(hasPage);
            model.zoomOut.enabled(hasPage);
            
            try {
                modelChangeGuard = true;
                
                $model.trigger("pageNumber", currentPageNumber);
                $model.trigger("pageCount", pageCount);
                
            } finally {
                modelChangeGuard = false;
            }
        }

        controller.currentPageChanged(function () {
            updateUI();
        });

        controller.beforeLoadReport(function () {
            updateUI();
        });

        controller.reportLoadProgress(function (e, args) {
            updateUI();
        });

        controller.reportLoadComplete(function (e, args) {
            updateUI();
        });

        controller.reportSourceChanged(function () {
            updateUI();
        });

        controller.exportStarted(function () {
            setState(stateFlags.ExportInProgress, true);
            updateUI();
        });

        controller.exportReady(function () {
            setState(stateFlags.ExportInProgress, false);
            updateUI();
        });

        controller.printStarted(function () {
            setState(stateFlags.PrintInProgress, true);
            updateUI();
        });

        controller.printReady(function () {
            setState(stateFlags.PrintInProgress, false);
            updateUI();
        });

        controller.viewModeChanged(function () {
            updateUI();
        });

        controller.setParameterAreaVisible(function () {
            updateUI();
        });

        controller.setDocumentMapVisible(function () {
            updateUI();
        });

        updateUI();
    };

    function command(execCallback) {
        var enabledState = true;
        var checkedState = false;

        var cmd = {
            enabled: function (state) {
                if (arguments.length == 0) {
                    return enabledState;
                }
                var newState = Boolean(state);

                // TODO: The event should not be triggered always. However, at the moment the state is not refreshed correctly if there is a check.
                enabledState = newState;
                $(this).trigger("enabledChanged");

                return cmd;
            },

            checked: function (state) {
                if (arguments.length == 0) {
                    return checkedState;
                }

                var newState = Boolean(state);

                // TODO: The event should not be triggered always. However, at the moment the state is not refreshed correctly if there is a check.
                checkedState = newState;
                $(this).trigger("checkedChanged");

                return cmd;
            },

            exec: execCallback
        };

        return cmd;
    }
    
    trv.toolsModel = toolsModel;
    trv.toolsController = toolsController;

}(window.telerikReportViewer = window.telerikReportViewer || {}, jQuery, window, document));