/*stuff for JSLint: http://www.jslint.com/ */
/*jslint browser: true */
/*global googleExercise,  CSSClass */

// Create the namespace object.
var googleExercise;
if (!googleExercise) {
    googleExercise = {};
}

// Note that we use an unnamed function so we don't create any other global symbols.
(function () { // Begin anonymous function definition
    
    //General config object minimizes magic string references, a simple way to keep things tidy
    var config = {
        containerIdKey: 'contacts',
        itemIdKey: 'item',
        displayByKey: 'displayBy',
        sortByKey: 'sortby',
        chatsEmailLinkString: 'Chats'.link() + ' -  ' + 'Emails'.link(),
        mapLinkUrl: 'http://maps.google.com/maps?f=q&hl=en&q=',
        mapLinkString: 'map',
        showLineItemClassName: 'show-details',
        dimItemsClassName: 'dim-items',
        detailsClassName: 'details',
        displayByClassName: 'container-sortby'
    };
    
    //If a config has been defined externally then augment our existing config object
    if (googleExercise.config) {
        config = googleExercise.config;
    }
    
    var container;
    var contacts = googleExercise.contacts; //Importing contacts as JSON object from GoogleExerciseData.js
    var activeElement;
    var isIE = false;
    var displayByElement;
    
    googleExercise.Load = function () {
        //Find our container element after the window has loaded
        container = document.getElementById(config.containerIdKey);
        
        //Call our procedures
        loadContacts();
        loadDisplayBy();
    };
    
    function loadContacts() {
        container.innerHTML = '';
        
        for (var i = 0 ; i < contacts.length ; i += 1) {
            var lineItem = document.createElement('div');
            lineItem.id = config.itemIdKey + i;
            lineItem.className = config.itemIdKey;
            
            var itemExtraDetails = document.createElement('div');
            itemExtraDetails.className = config.detailsClassName;
            
            //I should probably be using an array of properties to indicate which object property I want
            // using a for in loop like this doesn't guarantee that my JSON object is in my implicit ordering
            for (var property in contacts[i]) {

                var contactItem = contacts[i][property];
                
                var item = document.createElement('div');
                item.id = property + i;
                item.className = property;
                
                if (property === 'email') { // for email create a mailto href link
                    var emailLink = document.createElement('a');
                    emailLink.href = 'mailto:' + contactItem;
                    emailLink.innerHTML = contactItem;
                    
                    item.appendChild(emailLink);
                } else if (property === 'address') { // for address create a map link
                    item.innerHTML = contactItem + ' - ';
                    
                    var delimiter = ',+';
                    var mapLink = document.createElement('a');
                    mapLink.href = config.mapLinkUrl + contacts[i].address + delimiter + contacts[i].city + delimiter + contacts[i].province;
                    mapLink.href += delimiter + contacts[i].postalCode + delimiter + contacts[i].country;
                    mapLink.innerHTML = config.mapLinkString;
                    
                    item.appendChild(mapLink);
                } else if (property === 'avatar') { // for avatar create an image
                    var avatarImage = document.createElement('img');
                    avatarImage.src = contactItem;
                    
                    item.appendChild(avatarImage);
                } else { 
                    if (property !== 'country') { // filter out country, not required, but included in contacts JSON data
                        item.innerHTML = contactItem;
                    }
                }
                
                if (property === 'name' || property === 'email') {
                    lineItem.appendChild(item);
                } else {
                    itemExtraDetails.appendChild(item);
                }
            }
            
            var chatEmailLink = document.createElement('div');
            chatEmailLink.innerHTML = config.chatsEmailLinkString;
            
            itemExtraDetails.appendChild(chatEmailLink);
            
            lineItem.appendChild(itemExtraDetails);
            
            container.appendChild(lineItem);
        };
        
        //Again using DOM Events Level 0 Traditional model
        container.onmouseover = function (event) {        
            var eventNode;
            
            if (!event) { // handel IE event model
                event = window.event;  
                eventNode = event.srcElement;
                isIE = true;
            } else {
                eventNode = event.target;
            }
            //I should be filtering out events when the additional details are being displayed, but I'm lazy
            if (eventNode) {
        
                var itemId = getItemId(eventNode);
                
                if (itemId) {

                    activeElement = document.getElementById(itemId);
                    
                    CSSClass.add(activeElement, config.showLineItemClassName);
                    CSSClass.add(container, config.dimItemsClassName);
                    
                    if (isIE) { //IE doesn't treat select elements very nice (they always float above the element) so lets hide the select (dropdown) element
                        displayByElement = document.getElementById(config.displayByKey);
                                        
                        var itemNumber = itemId.replace(config.itemIdKey, '');
                        
                        if (itemNumber > (contacts.length - 4)) {
                            CSSClass.add(displayByElement, 'hide');
                        }
                    }
                }
            }
        };
        
        //Again using DOM Events Level 0 Traditional model
        container.onmouseout = function (event) {
            //I should be filtering out events when the additional details are being displayed, but I'm lazy
            if (activeElement) {
                CSSClass.remove(activeElement, config.showLineItemClassName);
                CSSClass.remove(container, config.dimItemsClassName);
                
                if (isIE) { //IE doesn't treat select elements properly, so lets unhide the select (dropdown) element
                    CSSClass.remove(displayByElement, 'hide');
                }
            }
        };
        
        //Recursive call works it's way up the tree looking for an item id
        function getItemId(element) {
            if (element) {
                if (element.id === config.containerIdKey) {
                    return false;
                }
                if (element.id && element.id.indexOf(config.itemIdKey) !== -1) {
                    return element.id;
                } 
                return getItemId(element.parentNode);
            }
        };    
    };
    
    function loadDisplayBy() {
        
        var displayBy = document.createElement('select');
        displayBy.id = config.displayByKey;
        
        var option1 = document.createElement('option');
        option1.text = 'Email address';
        option1.value = 'email';

        var option2 = document.createElement('option');    
        option2.text = 'Phone number';
        option2.value = 'phone';
        
        try { //standards compliant
            displayBy.add(option1, null);
            displayBy.add(option2, null);
        }
        catch (ex) { //IE compliant
            displayBy.add(option1);
            displayBy.add(option2);
        }
        
        //Again using DOM Events Level 0 Traditional model
        displayBy.onchange = function () {

            for (var i = 0 ; i < contacts.length ; i += 1) {
                var thisNode = document.getElementById('phone' + i);
                var thatNode = document.getElementById('email' + i);

                swapNode(thisNode, thatNode);
            }
        };
               
        document.getElementById(config.sortByKey).appendChild(displayBy);
    };
    
    function swapNode(thisNode, thatNode) {
        var nextSibling = thatNode.nextSibling;
        var parentNode = thatNode.parentNode;
        thisNode.parentNode.replaceChild(thatNode, thisNode);
        parentNode.insertBefore(thisNode, nextSibling);  
    };

})(); // End anonymous function definition and invoke it

/*members Load, add, address, appendChild, chatsEmailLinkString, city, 
    className, config, contacts, containerIdKey, country, createElement, 
    detailsClassName, dimItemsClassName, displayByClassName, displayByKey, 
    event, getElementById, href, id, indexOf, innerHTML, insertBefore, 
    itemIdKey, length, mapLinkString, mapLinkUrl, nextSibling, onchange, 
    onmouseout, onmouseover, parentNode, postalCode, province, remove, 
    replace, replaceChild, showLineItemClassName, sortByKey, src, 
    srcElement, target, text, value
*/