﻿/*
ALM II Customizable Home page v.1.0.0.14
Pending changes/bugs:
    * RSS configuration by the user
    * Dashboard widgets should have a minimize/close button
    * Add an optional toolbar/navigation bar to open dashboard widgets

Changes:
    * Replaced adding a new tab into a different dialog - per Oren recommendation
    * Fixed some UI bugs and glitches
    * Removed Options.html page as it was mainly used as an aid in the new dialog development
    * If the user clicks a home page link to a product we may support a new matching tab will be added
    * Add google+ like home page mock up a left pane with the following basic design:
        ┌─────┐
        │     │ <u>user name</u>
        │     │
        └─────┘
        Systems:
        ◌ SVN
        ◌ Bugzilla
        ◌ Hudson
        ◌ Nexus

        Teams:
        ◌ My Team
        ◌ My Product
        ◌ My Company

    * Added a Dashboard with some sample of external widgets.
    * Fixed opening links bug
    * Added a "Post Action" comment dynamic link, only reveals itself when user hovers over post
    * Home page top menu section is now static, thus it will always stays on top
    * Added another RSS posts like, from Sonar and Nexus
    * Added a Goggle+ like scheme (partial), user avatar and name are available
    * Home page improved, added the Share/Contribute box.
    * Fixed alignments of Systems (with icons) and Teams (no icons)
    * Clicking on a link (either an internal post link) or a System link would either open up a new tab
      with the matching system or use an already existing tab
    * Drop down control has been redesigned and coded. It's only current bug is that it's
      list cannot open above other elements.
    * When a RSS feed based linked is clicked (attached link) the script checks if a corresponding tab
      is already open, in that case, the link will open internally in the tab
    * Fixed iFrame positioning and resizing
    * Added a sorted smart list to trace user's tab clicks so closing tabs has some visible logic
    * Added "dynamic" iFrames which preserve user's browsing, tab click now switches iFrames, not URLs
    * Main cookie is now saved with a JSON based array
    * JSON parser is used
    * Add an option to fix URLs typed by the user:
        - Complete http://
        - Complete www

        - For some reason iFrame do not accept partial URLs
    * Preserve typed URLs (fixed) and add them to drop-down
    * Fixed some bugs when closing a non-focused iFrame
    * Changed tab close button to act as a hover button

Features List:
    * Demonically add/remove tabs that are used for in-browser browsing
    * Store recent tab specifications on client machine using localStorage
    * Offer the user some pre-defined URLs for common Tikal services


*/

/* 
Bugzilla http://dev.tikalk.com/bugzilla2010/
SVN http://dev.tikalk.com/viewvc/bin/cgi/viewvc.cgi
Hudson http://dev.tikalk.com/hudson/
Nexus http://dev.tikalk.com/nexus/index.html#welcome
*/

var Tikal = {
    services: [],
    preDefinedUrls: [
        {
            key: 'Bugzilla',
            value: 'http://localhost/bugzilla/',
            rss: 'http://localhost/bugzilla/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&cf_target_version=2011.2-SNAPSHOT&product=tikal-alm&query_format=advanced&title=Issue%20List&ctype=atom'
        },
        {
            key: 'SVN',
            value: 'http://localhost/viewvc/bin/cgi/viewvc.cgi',
            rss: 'http://localhost/viewvc/bin/cgi/viewvc.cgi/svn/?date=month&view=query&format=rss'
        },
        {
            key: 'Jenkins',
            value: 'http://localhost/jenkins/',
            rss: 'http://localhost/jenkins/rssAll'
        },
        {
            key: 'Nexus',
            value: 'http://localhost/nexus/index.html#welcome',
            rss: 'http://localhost/nexus/service/local/feeds/recentlyCachedOrDeployedArtifacts'
        }
    ],
    selectedTabName: '', /* Used to store the currently selected tab, useful when tab is closed */
    serviceIFrames: [],
    morePreDefinedUrls: []
};

Tikal.Utils = new function () {
    this.frameHeight = 0;

    // Utility, search the saved service by key, return it's URL
    this.GetValueByKey = function (arr, key) {
        var index, n = arr.length;

        for (index = 0; index < n; index++) {
            if (arr[index] == key) {
                return (arr[index + 1]);
            } else {
                index++;
            }
        }
    };

    this.GetValueByKeyJSON = function (arr, key) {
        return (Tikal.Utils.GetObjectByKeyJSON(arr, key).value);
    };

    this.GetObjectByKeyJSON = function (arr, key) {
        var index, n = arr.length;

        for (index = 0; index < n; index++) {
            if (arr[index].key == key) {
                return (arr[index]);
            }
        }
    };

    // If the useKey flag is up, compare with keys, otherwise compare with values
    this.DoesKeyExistsJSON = function (arr, key, useKey) {
        var index, n = arr.length;

        if (n == 0) {
            return (false);
        }

        for (index = 0; index < n; index++) {
            if (useKey) {
                if (arr[index].key.toLowerCase() == key) {
                    return true;
                }
            } else {
                if (arr[index].value == key) {
                    return true;
                }
            }
        }
        return (false);
    };

    this.RemoveElement = function (arr, elem) {
        var idx, n = arr.length;
        for (idx = 0; idx < n; ++idx) {
            if (arr[idx] != elem) {
                continue;
            }
            break;
        }

        if (idx < arr.length) { // the element was found
            arr.splice(idx, 1);
        }
    };

    this.RemoveElementJSON = function (arr, elem) {
        var idx, n = arr.length;
        for (idx = 0; idx < n; ++idx) {
            if (arr[idx].value != elem) {
                continue;
            }
            break;
        }

        if (idx < arr.length) { // the element was found
            arr.splice(idx, 1);
        }
    };

    // This method tries to find a URL in pre-loaded collection, current saved services and current displayed services
    // The bottom line is we want to establish what should we do with this URL, add it to pre loaded collection or not
    this.DoesURLAlreadyExists = function (services, predefinedURLs, url) {

        // Does this URL already in our current session? If so, return
        if (Tikal.Utils.DoesKeyExistsJSON(services, url)) {
            return (true);
        }

        // Does this URL originated from the pre-loaded value? If so, return
        if (Tikal.Utils.DoesKeyExistsJSON(predefinedURLs, url)) {
            return (true);
        }

        // Otherwise, return false
        return (false);
    };

    this.ValidateURL = function (urlToValidate) {
        var urlregex = new RegExp();
        urlregex.compile("^[A-Za-z]+://[A-Za-z0-9-_]+\\.[A-Za-z0-9-_%&\?\/.=]+$");
        return urlregex.test(urlToValidate);
    };

    // Try to fix URL
    this.FixURL = function (url) {
        var http = 'http://';
        var www = 'www.';

        // If url is valid, just return it
        if (Tikal.Utils.ValidateURL(url)) {
            return (url);
        }

        // Look up protocol (http), if it's missing add it in front of the URL
        if (!url.startsWith(http)) {
            url = http + url;
        }

        // Look up world wide web (www) part, if it's missing insert it
        if (url.indexOf(www) == -1) {
            var address = url.substring(http.length, url.length);
            url = http + www + address;
        }

        return (url);
    };

    this.CalculateCurrentWindowHeight = function () {
        var frameTop = $('.hpMainContent').position().top + 5;
        Tikal.Utils.frameHeight = $(window).height() - frameTop - 1;
    };

};

Tikal.Utils.Links = new function () {
    
    this.ifTabAlreadyExistsOpenIt = function (url) {
        var existingIframeId = Tikal.Utils.Links.getOpenTabNameIfItMatchesURL(url, Tikal.services);
        if (existingIframeId) {
            var tab = document.getElementById(existingIframeId.key);
            // Emulate a tab click
            Tikal.Utils.Tabs.dynamicLinkClicked(tab, url);
            return (true);
        }        
        return (false);
    };

    this.getOpenTabNameIfItMatchesURL = function (url, links) {
        // First remove the http:// string from the original url
        var linkDomain = (url.match(/:\/\/(.[^/]+)/)[1]).replace('www.','');
        var linkOtherParts = url.split(linkDomain); // Separate the domain name (element 0 in this array from the rest of the url)
        if (linkOtherParts.length > 1) {
            // Now parse the rest of the domain into particles
            linkOtherParts = linkOtherParts[1].split('/');
        }

        var index, n = links.length;
        for (index = 0; index < n; index++) {
            var serviceDomain = (links[index].value.match(/:\/\/(.[^/]+)/)[1]).replace('www.','');
            var serviceURLParts = links[index].value.split(serviceDomain);

            if (serviceURLParts.length > 1) {
                // Now parse the rest of the domain into particles
                serviceURLParts = serviceURLParts[1].split('/');
            }
            if ((serviceURLParts.length > 1) && (linkOtherParts.length > 1)) {
                if ((linkOtherParts[1].length > 1) && (serviceURLParts[1].length > 1)) {
                    if (linkOtherParts[1].startsWith(serviceURLParts[1])) {
                        return (links[index]);
                    }
                }
            }
        }
        return (undefined);
    };

    this.tryAddingANewTab = function(url) {
        var isServicePreDefined = Tikal.Utils.Links.getOpenTabNameIfItMatchesURL(url, Tikal.preDefinedUrls);
        if (isServicePreDefined) {
            Tikal.Utils.Tabs.appendTab(isServicePreDefined.key);

            Tikal.Utils.Tabs.storeNewTab(isServicePreDefined.key, url);
            var tab = document.getElementById(isServicePreDefined.key);
            // Emulate a tab click
            Tikal.Utils.Tabs.dynamicLinkClicked(tab, url);
            return (true);
        }        

        return (false);
    }
};

Tikal.Utils.LocalStore = new function () {

    // storeNewTab the services in a cookie
    this.saveServicesToStore = function () {
        // First invalidate the old store
        amplify.store('Tikal_ALMII_services', null);

        // Save the services to store
        amplify.store('Tikal_ALMII_services', Tikal.services);
    };

    // Reload the services back from cookie
    this.reloadSavedServices = function () {
        var services = amplify.store('Tikal_ALMII_services');

        Tikal.services = (services instanceof Array ? services : []);
    };

    this.saveNewPreLoadOptions = function () {
        // First invalidate the old store
        amplify.store('Tikal_ALMII_More_PreLoads', null);

        // Save the more pre defined URLs to store
        amplify.store('Tikal_ALMII_More_PreLoads', Tikal.morePreDefinedUrls);
    }

    this.reloadMorePreloadedOptions = function () {

        // Pull the pre defined URLs from store
        var morePreloaded = amplify.store('Tikal_ALMII_More_PreLoads');

        if (morePreloaded instanceof Array) {
            Tikal.morePreDefinedUrls = morePreloaded;
            Tikal.preDefinedUrls.append(Tikal.morePreDefinedUrls);
        }
    }
};

Tikal.Utils.Tabs = new function () {
    this.dynamicLinkClicked = function (element, url) {
        if ($('.hpMainContentSocail').is(":visible")) {
            $('.hpMainContentSocail').fadeOut(500);
        }

        if ($('.personal').is(":visible")) {
            $('.personal').fadeOut(400);
        }

        if ($('.dashboard-div').is(":visible")) {
            $('.draggable').fadeOut(500);
            $('.dashboard-div').slideUp("slow");
        }

        Tikal.Utils.Tabs.unselectDynamicTabs();
        $(element).addClass("selected");
        Tikal.Utils.MRV.Add(element.id); // Log every tab selection in the Most Recently Viewed collection

        Tikal.Utils.iFrame.showServiceIFrame(element.id, Tikal.Utils.GetValueByKeyJSON(Tikal.services, element.id), url);
    };

    // Clear all the selected tabs selection class - UI operation
    this.unselectDynamicTabs = function () {
        $('div.topMenu').find('li').each(function (index) {
            $(this).removeClass("selected");
        });
    };

    this.loadPredefinedURLs = function () {
        var dropdown = document.getElementById('serviceURLSelect');
        // Clear options
        dropdown.options.length = 0;
        $.each(Tikal.preDefinedUrls, function (id, element) {
            dropdown.options[dropdown.options.length] = new Option(element.value, element.key);
        });
    };

    this.reloadTabs = function () {
        // If services exists, reload them and restore them
        if (Tikal.services) {

            // Remove the plus button so we can place later back in it's place
            var index, n = Tikal.services.length;
            for (index = 0; index < n; index++) {
                // Append the new child
                Tikal.Utils.Tabs.appendTab(Tikal.services[index].key);
            }
        }
    };

    this.appendTab = function (tabName) {

        // Append the new child
        $("#topMenuUL").append('<li id="' + tabName + '"><span class="corL"></span><a href="#">' + tabName +
            '</a>&nbsp;&nbsp;&nbsp;<a href="#" class="closeKey" id="close' + tabName + '" onclick="Tikal.Utils.Tabs.removeTab(this);" >x</a><span class="corR"></span></li>');

        // Attach the correct click event
        $("#" + tabName).bind({
            'click': function () {
                Tikal.Utils.Tabs.dynamicLinkClicked(this);
            }
        });

        $("#" + tabName).hover(
            function () {
                $($("#close" + tabName)).addClass('hover');
            },
            function () {
                $($("#close" + tabName)).removeClass('hover');
            }
        );

        $("#close" + tabName).click(function () {
            Tikal.Utils.Tabs.removeTab(this);
        });
    };

    this.storeNewTab = function (tabName, url, rss) {
        // Ensure that the array exists
        if (!Tikal.services) {
            Tikal.services = [];
        }

        var service = {
            'key': tabName,
            'value': url,
            'rss': rss
        };

        if (!Tikal.Utils.DoesURLAlreadyExists(Tikal.services, Tikal.preDefinedUrls, url)) {
            Tikal.preDefinedUrls.push(service);     // Add service to current drop down
            Tikal.morePreDefinedUrls.push(service); // Add service to more pre-defined collection (saved to cookie)
            Tikal.Utils.Tabs.loadPredefinedURLs();

            // Save the pre-loaded
            Tikal.Utils.LocalStore.saveNewPreLoadOptions();
        }

        // Add service to current open services/tabs
        Tikal.services.push(service);

        // Save the current services into cookies
        Tikal.Utils.LocalStore.saveServicesToStore();
    };

    this.removeTab = function (element) {
        var serviceId = element.parentNode.id;
        // If the currently opened tab is being removed, close the iframe and go back home
        var isCurrentTabClosing = (Tikal.selectedTabName == serviceId);
        var numberOfCreatedTabs = Tikal.Utils.MRV.GetSortedList().length;

        // Append the new child
        $("#" + element.parentNode.id).remove();
        var service = Tikal.Utils.GetValueByKeyJSON(Tikal.services, serviceId);

        Tikal.Utils.RemoveElementJSON(Tikal.services, service);

        Tikal.Utils.MRV.Delete(serviceId); // Remove tab from the Most Recently Viewed collection

        Tikal.Utils.LocalStore.saveServicesToStore();

        if (numberOfCreatedTabs == 0) {
            isCurrentTabClosing = false; // Invalidate, no more iFrames to show
            // Minimize the last iFrame
            var iFrameElement = document.getElementById('frame_' + Tikal.selectedTabName);
            iFrameElement.style.height = 0;
            Tikal.Utils.Tabs.restoreHomePage();
        }

        // Finally remove the iFrame
        Tikal.Utils.iFrame.closeServiceIFrame(serviceId);

        if (isCurrentTabClosing) {
            Tikal.Utils.Tabs.restoreHomePage();
            if (numberOfCreatedTabs > 0) { // Only try to restore a tab if it exists
                // Use the Most Recently Viewed collection and open the last tab the user has visited
                Tikal.Utils.Tabs.dynamicLinkClicked($('#' + Tikal.Utils.MRV.GetTopMostElement().obj)[0]);            
            }
        }
    };

    this.restoreHomePage = function () {
        $('.personal').fadeIn(500);
        $('.hpMainContentSocail').fadeIn(500);
    };

    this.showDashboard = function () {
        if ($('.hpMainContentSocail').is(":visible")) {
            $('.hpMainContentSocail').fadeOut(500);
        }

        if (!$('.personal').is(":visible")) {
            $('.personal').fadeIn(400);
        }

        Tikal.Utils.Tabs.unselectDynamicTabs();

        $('.dashboard').addClass("selected");

        $(".draggable").draggable();
        $(".draggable").resizable();

        $(".dashboard-div").height(Tikal.Utils.frameHeight);
        Tikal.Utils.iFrame.minimizeCurrentIFrame();

        $('.draggable').show("slow");
        $('.dashboard-div').slideDown("slow");        
    };

};

Tikal.Utils.iFrame = new function () {

    this.onResizeWindow = function (applyResize) {
        Tikal.Utils.CalculateCurrentWindowHeight();

        if (applyResize) {
            $('frame_' + Tikal.selectedTabName).height(Tikal.Utils.frameHeight + 'px');
        }
    };

    this.minimizeCurrentIFrame = function () {

        var iFrameElement;
        // Ensure that the array exists
        if (!Tikal.serviceIFrames) {
            Tikal.serviceIFrames = [];
        } else {
            // If the service IFrame array isn't empty there must be at least one iframe already in existence, hide the current iframe
            if (Tikal.selectedTabName) {
                iFrameElement = document.getElementById('frame_' + Tikal.selectedTabName);
                iFrameElement.style.height = 0;
            }
        }
    };


    this.showServiceIFrame = function (serviceId, initialURL, reloadURL) {
        try {

            Tikal.Utils.iFrame.minimizeCurrentIFrame();
            Tikal.Utils.iFrame.onResizeWindow();

            var iFrame = Tikal.Utils.GetObjectByKeyJSON(Tikal.serviceIFrames, serviceId);

            if (!iFrame) {
                var newIFrame = new Tikal.Utils.iFrame.iFrameObject(serviceId);
                // Push the values into the array, this is a bit lame
                Tikal.serviceIFrames.push(newIFrame);

                iFrame = $('<iframe id="frame_' + serviceId + '" width="100%" frameborder="0" scrolling="auto" style="top: ' + Tikal.Utils.frameTop + 'px; position: fixed;" />');
                iFrame.attr('src', initialURL);
                iFrame.appendTo($('.hpMainContentCenter'));
            }

            iFrameElement = document.getElementById('frame_' + serviceId);

            if (reloadURL) {
                iFrameElement.setAttribute('src', reloadURL);
            }

            Tikal.selectedTabName = serviceId;
            // Add the new service tab name to the Most Recently Viewed collection            
            Tikal.Utils.MRV.Add(serviceId);
            iFrameElement.style.height = Tikal.Utils.frameHeight + 'px';

        } catch (e) {
            alert('Tikal.Utils.iFrame, showServiceIFrame' + e);
        }
    };

    this.closeServiceIFrame = function (serviceId) {
        var iFrameElement = document.getElementById('frame_' + serviceId);
        if (iFrameElement) {
            iFrameElement.style.height = '0%';
            $('.hpMainContentCenter').remove(iFrameElement);
        }
    };
}

// Manage a Most Recently Viewed list
// This list traces user's tab clicks (the tab itself, not inside the pages)
// This list purpose is to enable
Tikal.Utils.MRV = new function () {
    var _maxListSize = 20;
    var _topMostIndex = -1;

    var _list = [];
    var _sorted = false;

    this.Add = function (element) {
        _topMostIndex++;

        var elementIndex = Tikal.Utils.MRV.Find(element);

        if (elementIndex >= 0) {
            _list[elementIndex].index = _topMostIndex;
        } else {
            var mrvElement = new Tikal.Utils.MRV.element;
            mrvElement.obj = element;
            mrvElement.index = _topMostIndex;
            // If we have reached the maximum list count, remove the first element to
            // make room for the new comer
            if (_list.length > _maxListSize) {
                _list.splice(0, 1);
            }
            _list.push(mrvElement);
            _sorted = false;
        }
    },

    this.Find = function (element) {
        var index, n = _list.length;
        for (index = 0; index < n; index++) {
            if (_list[index].obj == element) {
                return (index);
            }
        }
        return (-1);
    },

    this.Delete = function (element) {
        var elementIndex = Tikal.Utils.MRV.Find(element);
        if (elementIndex) {
            _list.splice(elementIndex, 1);
        }
    },

    this.GetSortedList = function () {
        _sorted = true;
        return (_list.reverse(Tikal.Utils.MRV.SortByTopMostIndex));
    },

    this.GetTopMostElement = function () {
        var topMostElement = Tikal.Utils.MRV._list[0];

        if (!_sorted) {
            _list = Tikal.Utils.MRV.GetSortedList();
            topMostElement = _list[0];
        }

        return (topMostElement);
    },

     this.SortByTopMostIndex = function (a, b) {
         var x = a.index;
         var y = b.index;

         return ((x < y) ? -1 : ((x > y) ? 1 : 0));
     }
};

Tikal.Utils.MRV.element = function () {
    this.index = 0;
    this.obj = 'undefined';
};

Tikal.Utils.iFrame.iFrameObject = function (key) { 
    this.key = key;
    this.toString = function () {
        return ('frame_' + key);
    }
 };
