﻿/// <reference path="ext-base.js"/>
/// <reference path="ext-all.js"/>

/*
    MIT License

    Copyright (c) 2009 Mats Bryntse

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
*/
 
// Boot strap code
Ext.onReady(function() {
    if (Ext.isIE) {
        Ext.Msg.alert('IE not supported', 'This application is only tested in FF3 and Chrome');
        return;
    }

    var app = new Globals.App();
    app.init();
});

Ext.namespace('Globals');

Globals.App = function() {
    Ext.BLANK_IMAGE_URL = 'http://extjs.cachefly.net/ext-2.2/resources/images/default/s.gif';
    Ext.QuickTips.init();

    // Singleton scanner object
    Globals.scanner = function() {
        var scanner = new Globals.IframeScanner();
        return {
            getInstance: function() {
                return scanner;
            }
        };
    }();

    return {
        init: function() {
            var matrixButton = new Ext.Toolbar.Button({
                iconCls: 'table',
                text: 'Show collision matrix',
                ctCls: 'x-btn-over3',
                scope: this,
                handler: function() {
                    // First check if user has selected >= 2 rows
                    var selectedRecords = this.apiGrid.getSelectionModel().getSelections();
                    if (!selectedRecords || selectedRecords.length < 2) {
                        Ext.Msg.alert('Error', 'You have to select at least 2 frameworks to analyze!');
                        return;
                    }
                    
                    var selectedRowIndexes = [];
                    var s = this.apiGrid.store;
                    
                    Ext.each(selectedRecords, function(r) {
                        selectedRowIndexes.push(s.indexOf(r));    
                    });
                    
                    var matrixWin = new Globals.CollisionMatrixWindow(this.apiGrid.store, selectedRowIndexes);
                    matrixWin.on('show', matrixWin.maximize, matrixWin);
                    matrixWin.show();
                    matrixWin.scanForCollisions.defer(100, matrixWin);
                }
            });

            // Using a snapshot instead
//            var apis = [];

//            // Populate the grid store from the config object
//            Ext.each(Globals.apiConfig, function(api) {
//                apis.push([api.id, api.name, '', '', '', '', api.versions, api.scripts, '', api.styleSheets || '', api.dependencies]);
//            });

            this.apiGrid = new Globals.ApiGrid({
                region: 'center',
                store: new Ext.data.SimpleStore({
                    fields: ['id', { name: 'name', type: 'string' }, 'globalcount', 'augmentationcount', 'csscount', 'version', 'versions', 'scripts', 'symbols', 'styleSheets', 'dependencies'],
                    sortInfo: { field: 'name', direction: 'ASC' },
                    data: Globals.apiSnapshot
                })
            });

            this.apiGrid.on('validateedit', function(e) {
                e.record.set(e.field, e.value);
                this.scan(e.record, true);
            }, this);

            this.detailsGrid = new Globals.DetailsGrid({
                split: true,
                width: 300,
                region: 'east',
                store: new Ext.data.GroupingStore({
                    reader: new Ext.data.ArrayReader({}, [
                    { name: 'name', type: 'string' },
                    { name: 'type', type: 'string' },
                        'value',
                        'category'
                    ]),
                    groupField: 'category',
                    sortInfo: { field: 'name', direction: 'ASC' }
                })
            });

            this.apiGrid.on('rowclick', function(g, rowIndex, e) {
                // Disregard check-column click events
                var t = Ext.fly(e.getTarget());
                if(t.hasClass("x-grid3-row-checker")){
                    return;
                }
                
                var symbols;
                var rec = g.store.getAt(rowIndex);
                var id = rec.get('id');

                symbols = rec.get('symbols');

                if (symbols && rec.get('globalcount')) {
                    this.detailsGrid.load.defer(10, this.detailsGrid, [symbols]);
                }
            }, this);

            this.mainWin = new Ext.Window({
                height: 500,
                width: 1100,
                layout: 'border',
                closable: false,
                maximizable: true,
                closeAction: 'hide',

                title: '<table cellspacing="0" cellpadding="0"><tr><td>FrameworkScanner v0.3 </td><td style="padding-left:20px"><div id="prog"></div></td></tr></table>',
                items: [
                {
                    region: 'west',
                    width: 300,
                    frame: true,
                    bodyStyle: 'padding:5px',
                    autoScroll: true,
                    autoLoad: 'text.htm'
                },
                    this.apiGrid,
                    this.detailsGrid
                ],
                tbar: new Ext.Toolbar({
                    items: [
                        '  ',
                        matrixButton,
                        '        ',
                    {
                        iconCls: 'scripts',
                        ctCls: 'x-btn-over3',
                        text: 'Analyze your own scripts',
                        handler: function() {
                            var win = new Globals.CustomScriptWindow();

                            win.on('dataentered', function(w, text) {
                                if (!text) {
                                    return;
                                }

                                delete Globals.matrixSnapshot;
                                Globals.matrixSnapshot = [];

                                var rec = new Ext.data.Record.create(['id', { name: 'name', type: 'string' }, 'globalcount', 'augmentationcount', 'csscount', 'version', 'versions', 'scripts', 'symbols', 'styleSheets', 'dependencies']);

                                this.apiGrid.store.addSorted(new rec({
                                    id: Ext.util.Format.htmlEncode(text),
                                    name: Ext.util.Format.htmlEncode(text),
                                    versions: [
                                    {
                                        scripts: [text],
                                        styleSheets: []
                                    }
                                    ]
                                }));

                                // Find the record in the store
                                var index = this.apiGrid.store.find('id', Ext.util.Format.htmlEncode(text));

                                // Scan just this one
                                this.scan(this.apiGrid.store.getAt(index), true);
                            }, this);

                            win.show();
                        },
                        scope: this
                    },
                    '        ',
                    {
                        iconCls: 'run',
                        ctCls: 'x-btn-over3',
                        text: 'Start analysis',
                        handler: function() {
                            this.scan(this.apiGrid.store.getAt(0));
                        },
                        scope: this
                    },
                        '->',
                    {
                        iconCls: 'information',
                        ctCls: 'x-btn-over3',
                        text: 'What is being analyzed?',
                        handler: function() {
                            var sortedSymbols = Globals.nativeSymbols.sort(function(x, y) {
                                var a = String(x).toUpperCase();
                                var b = String(y).toUpperCase();
                                if (a > b)
                                    return 1;
                                if (a < b)
                                    return -1;
                                return 0;
                            });

                            var html = 'All the symbols below are being analyzed. If you know of more symbols that would fit in this list please send me an email.<br/><br/><ul><li>' +
                                            sortedSymbols.join('</li><li>') + '</li></ul>';

                            var infoWin = new Ext.Window({
                                height: 400,
                                width: 400,
                                autoScroll: true,
                                modal: true,
                                bodyStyle: 'padding:10px',
                                cls: 'infowin',
                                iconCls: 'information',
                                title: 'What\'s being analyzed?',
                                html: html
                            });
                            infoWin.show();
                        },
                        scope: this
                    },
                    {
                        text: 'Show grid JSON',
                        hidden: window.location.search.length === 0,
                        ctCls: 'x-btn-over3',
                        handler: function() {
                            var arr = [];

                            this.apiGrid.store.each(function(r) {
                                var row = [];
                                Ext.each(r.fields.keys, function(f) {
                                    row.push(r.get(f));
                                });
                                arr.push(row);
                            });

                            new Ext.Window({
                                height: 500,
                                width: 600,
                                plain: true,
                                autoScroll: true,
                                html: Ext.util.Format.htmlEncode(Ext.encode(arr))
                            }).show();
                        },
                        scope: this
                    },
                    {
                        text: 'Show matrix JSON',
                        hidden: window.location.search.length === 0,
                        ctCls: 'x-btn-over3',
                        handler: function() {
                            var arr = [];

                            this.matrixWin.grid.store.each(function(r) {
                                var row = [];
                                Ext.each(r.fields.keys, function(f) {
                                    row.push(r.get(f));
                                });
                                arr.push(row);
                            });

                            new Ext.Window({
                                height: 500,
                                width: 600,
                                plain: true,
                                autoScroll: true,
                                html: Ext.util.Format.htmlEncode(Ext.encode(arr))
                            }).show();
                        },
                        scope: this
                    }
                    ]
                }),
                bbar: new Ext.Toolbar({
                    items: [
                    {
                        xtype: 'tbtext',
                        text: '&copy; 2009 Mats Bryntse'
                    },
                        '->',
                    {
                        iconCls: 'wordpress',
                        text: 'Blog',
                        tooltip: 'My blog',
                        ctCls: 'x-btn-over2',
                        handler: function() {
                            window.open('http://mankzblog.wordpress.com/', '_blank');
                        }
                    },
                        '   ',
                    {
                        iconCls: 'linkedin',
                        text: 'LinkedIn',
                        tooltip: 'My LinkedIn profile',
                        ctCls: 'x-btn-over2',
                        handler: function() {
                            window.open('http://www.linkedin.com/profile?viewProfile=&key=34819881&authToken=dZuX&authType=NAME_SEARCH&locale=en_US&srchindex=1&goback=%2Epsr_*1_mats+bryntse_*1_*1_*1_*1_*1_*1_*1_*1_Y_us_94123_*1_*1_*2_*2_*2_Y_Y_*1_Relevance', '_blank');
                        }
                    },
                        '   ',
                    {
                        iconCls: 'mail',
                        tooltip: 'Send me feedback',
                        text: 'Feedback',
                        ctCls: 'x-btn-over2',
                        handler: function() {
                            window.location = 'mailto://mats@mankz.com';
                        }
                    }
                    ]
                })
            });

            this.mainWin.show(Ext.getBody(), function() {

                this.progressBar = new Ext.ProgressBar({
                    width: 150,
                    hidden: true,
                    text: 'Analyzing...',
                    autoHeight: true,
                    renderTo: 'prog'
                });

            }, this);
        },

        /*
        scanSingleComplete:
        This function adds the result of the scan to the main grid store
        */
        scanSingleComplete: function(scanObj, globals, arg) {
            var record = arg.record;
            var store = this.apiGrid.store;
            var totalNbrApis = store.getCount();
            var currentIndex = store.indexOf(record);
            var pctDone = currentIndex / (this.apiGrid.store.getCount() - 1);

            this.progressBar.updateProgress(pctDone, String.format('Analyzing {0}%', Math.round(pctDone * 100)));

            // Save the globals data in the global config object
            record.set('symbols', globals);

            var globalCount = 0;
            var augmentCount = 0;

            Ext.each(globals, function(g) {
                if (g.category === 'Global symbols') {
                    globalCount++;
                } else if (g.category === 'Native class augmentations' ||
                           g.category === 'Overriden native functions') {
                    augmentCount++;
                }
            });

            record.set('globalcount', globalCount);
            record.set('augmentationcount', augmentCount || '');
            record.set('csscount', (globals.length - globalCount - augmentCount) || '');

            record.commit();

            currentIndex++;

            if (!arg.single && currentIndex < totalNbrApis) {
                this.scan(this.apiGrid.store.getAt(currentIndex));
            } else {
                // We're done
                this.progressBar.hide();
                var t = this.mainWin.getTopToolbar();
                t.setDisabled(false);
                t.getEl().highlight();
                this.matrixWinStale = true;
            }
        },

        /*
        scan:
        This function iterates through the objects in the global config object
        containing all the frameworks and scripts
        */
        scan: function(record, single) {
            if (this.apiGrid.store.indexOf(record) === 0) {
                // Disable toolbar while scanning
                var t = this.mainWin.getTopToolbar();
                t.setDisabled(true);

                // Reset and show progress bar
                this.progressBar.reset().show();
            }

            record.set('globalcount', 'Loading...');
            record.commit();

            var scanner = Globals.scanner.getInstance();
            var vName = record.get('version');
            var scripts;
            var styleSheets;
            var ind = 0;

            if (vName) {
                Ext.each(record.get('versions'), function(v, i) {
                    if (v.name === vName) {
                        ind = i;
                        return false;
                    }
                });
            }
            var selectedVersionObj = record.get('versions')[ind];

            scanner.loadScripts(selectedVersionObj.scripts,
                                selectedVersionObj.styleSheets,
                                this.scanSingleComplete,
                                this,
            {
                record: record,
                single: single || false
            });
        }
    };
};
