// make sure jquery is defined
if (typeof('$') == 'undefined') throw new Error('JQuery must be included properly in order for the application to work.');

function openCompanyCarAdviceToolOnLoad()
{
    var href = location.href;

    if (href) {

        // disable bannercolumn (due to swf's showing through)
        // TODO: fix this the proper way with CSS
        if (document.getElementById('bannercolumn')) {
            document.getElementById('bannercolumn').style.visibility = 'hidden';
        }

        (new CompanyCarAdviceTool(href)).init();
    }
}
function openCompanyCarAdviceTool(e)
{
    if (e) cancelEvent(e);

    // disable bannercolumn (due to swf's showing through)
    // TODO: fix this the proper way with CSS
    if (document.getElementById('bannercolumn')) {
        document.getElementById('bannercolumn').style.visibility = 'hidden';
    }

    var target = getTarget(e);
    if (target.getAttribute('href')) {
        (new CompanyCarAdviceTool(target.getAttribute('href'))).init();
    }
}

function closeCompanyCarAdviceTool(e)
{
    if (e) cancelEvent(e);


    // ensable bannercolumn (disabled due to swf's showing through)
    // TODO: fix this the proper way with CSS
    if (document.getElementById('bannercolumn')) {
        document.getElementById('bannercolumn').style.visibility = 'visible';
    }

    var target = getTarget(e);

    // bubble up to tool node
    var tool = $(target).parents('.companycar-advicetool');
    if (tool.size() > 0) {
        var id = tool.attr('id');

        var toolObject = CompanyCarAdviceTool.findById(id);
        if (toolObject) {
            toolObject.destroy();
        }
    }
}

/**
 * Class-like function to create an interface for the site.
 *
 * @author Peter Kruithof
 */
function CompanyCarAdviceTool(hrefprefix)
{
    this.id = ++CompanyCarAdviceTool.COUNTER;
    this.currentHrefPrefix = hrefprefix || '';
    this.urlExtension = '.json';
    this.dataProvider = new DataProvider();
    this.views;
    this.currentView = 'side';

    this.getId = function()
    {
        return 'companycar-advicetool-' + this.id;
    }

    this.clickHandler = function(e)
    {
        if (window.event) cancelEvent(window.event);
        if (e) cancelEvent(e);

        // fetch uri
        var target = getTarget(e);
        if (target && target.getAttribute('href')) {
            this.loadContents(target.getAttribute('href'));
        }
    }

    /**
     * Loads content from an url. {@link CompanyCarAdviceTool.update} is called after contents are loaded.
     */
    this.loadContents = function(uri)
    {
        if (uri && (uri != '')) {

            // strip host
            uri = uri.replace(new RegExp(window.location.protocol + '//' + window.location.hostname), '');

            // strip trailing slash
            uri = uri.replace(/\/$/, '');

            this.currentHrefPrefix = uri;

            // fetch the uri
            this.dataProvider.fetch(uri + this.urlExtension);
        }
    }

    this.init = function()
    {
        // create interface
        var currentview = '<div class="currentview"><span>' + getText('CompanyCarsCurrentView') + '</span><p></p></div>';

        var view = '<div class="view-selector">';
        view += '<h3><span>' + getText('CompanyCarsChooseView') + '</span></h3>';
        view += '<div class="side"><p><span>' + getText('CompanyCarsViewSide') + '</span></p></div>';
        view += '<div class="front"><p><span>' + getText('CompanyCarsViewFront') + '</span></p></div>';
        view += '<div class="back"><p><span>' + getText('CompanyCarsViewBack') + '</span></p></div>';
        view += '</div>';

        var breadcrumbs = '';

        var close = '<div class="close"><p><span>' + getText('CompanyCarsClose') + '</span></p></div>';

        var html = '<div class="companycar-advicetool" id="' + this.getId() + '">';
        html += '<div class="body">';
        html += '<h2><span>MultiLease bedrijfswagens</span></h2>';
        html += '<div class="container">';
        html += '<div class="view">';
        html += '<div class="content"></div>';
        html += '<div class="companycar"></div>';
        html += '<p class="more-info"><a href="' + this.currentHrefPrefix + CompanyCarAdviceTool.infoUrlPart + '/" title="' + getText('LinkOpensInNewWindow') + '"><span>' + getText('CompanyCarsMoreInfo') + '</span></a></p>';
        html += '</div>';
        html += currentview;
        html += '</div>';
        html += view;
        html += '<div class="breadcrumbs">' + breadcrumbs + '</div>';
        html += close;
        html += '</div>';
        html += '</div>';

        $('#body').append(html);

        // view selection (click the current view)
        $('#' + this.getId() + ' .view-selector div').bind('click', Delegate.create(this, this.onSelectView));
        $('#' + this.getId() + ' .close').bind('click', closeCompanyCarAdviceTool);

        // listen to updates
        this.dataProvider.addEventListener('update', this.update, this);

        this.loadContents(this.currentHrefPrefix);
    }

    this.destroy = function()
    {
        // unbind events
        $('#' + this.getId() + ' *').unbind('click');

        // remove it
        $('#' + this.getId()).remove();

        delete CompanyCarAdviceTool.instances[this.getId()];
    }

    /**
     * Executes an update from the dataprovider. It processes the dataprovider's current section,
     * and puts the contents in dialog windows. If the fetched content is a subpage, it loads
     * that content into the existing dialog window.
     */
    this.update = function()
    {
        var section = this.dataProvider.getSection(this.currentHrefPrefix);

        if (section) {

            if (section.container_type == 'companycarsection') {

                var urlparts = this.dataProvider.getUrlPartsFromPath(this.currentHrefPrefix);
                var prefix = urlparts.join('/');

                // fill points
                if ('children' in section) {

                    var tmpviews = {'side' : {}, 'front' : {}, 'back' : {}};
                    tmpviews['side']['html'] = '<ol>';
                    tmpviews['front']['html'] = '<ol>';
                    tmpviews['back']['html'] = '<ol>';

                    tmpviews['side']['coords'] = {};
                    tmpviews['front']['coords'] = {};
                    tmpviews['back']['coords'] = {};

                    tmpviews['side']['styles'] = {};
                    tmpviews['front']['styles'] = {};
                    tmpviews['back']['styles'] = {};

                    for (var type in section.children) {

                        for (var a in section.children[type]) {

                            if (('coordinates' in section.children[type][a]) && (type in section.children[type][a]['coordinates'])) {

                                var href = '/' + prefix + '/' + a + '/';

                                var id = 'view-' + type + '-' + section.children[type][a]['container_id'];

                                tmpviews[type]['html'] += '<li id="' + id + '"><span class="num">' + section.children[type][a]['num'] + '</span>';
                                tmpviews[type]['html'] += '<div class="box"><div class="top"></div><div class="contents">';
                                tmpviews[type]['html'] += '<p class="title"><a href="' + href + '" title="' + section.children[type][a]['title'] + '"><span>' + section.children[type][a]['menutitle'] + '</span></a></p><p class="description">' + (section.children[type][a]['description'] || '') + '</p>';
                                tmpviews[type]['html'] += '</div><div class="bottom"></div></div>';
                                tmpviews[type]['html'] += '</li>';

                                tmpviews[type]['coords'][id] = section.children[type][a]['coordinates'][type];

                                // set backgrounds
                                if ('title_background' in section.children[type][a]) {
                                    tmpviews[type]['styles'][id] = section.children[type][a].title_background;
                                }
                            }
                        }
                    }

                    tmpviews['side']['html'] += '</ol>';
                    tmpviews['front']['html'] += '</ol>';
                    tmpviews['back']['html'] += '</ol>';

                    this.views = tmpviews;

                    this.selectView(this.currentView);
                }

            } else if (section.container_type == 'companycarsubsection') {

                // load body in content pane
                var html = '';
                html += '<h3 class="title"><span>' + section.title + '</span></h3>';
                html += '<h4 class="subtitle"><span>' + section.subtitle + '</span></h4>';
                html += section.body;

                if ('children' in section) {

                    html += '<ul class="submenu">';

                    for (var a in section.children) {
                        html += '<li><a href="' + section.children[a].url + '" title="' + section.children[a].title + '">' + section.children[a].menutitle + '</a></li>';
                    }

                    html += '</ul>';
                }

                $('#' + this.getId() + ' .content').html(html);
                $('#' + this.getId() + ' .content a').bind('click', Delegate.create(this, this.clickHandler));

                // set backgrounds
                if ('title_background' in section) {
                    $('#' + this.getId() + ' .content h3.title').css('background-image', 'url(' + section.title_background + ')');
                }
                if ('subtitle_background' in section) {
                    $('#' + this.getId() + ' .content h4.subtitle').css('background-image', 'url(' + section.subtitle_background + ')');
                }
            }

            var breadcrumbs = this.dataProvider.getBreadCrumbsFromPath(this.currentHrefPrefix);
            this.rebuildBreadcrumbs(breadcrumbs);
        }
    }

    this.onSelectView = function(e)
    {
        if (e) {
            var target = getTarget(e);
            var className = target.className;

            // extract view from class
            this.selectView(className.replace(/view\-/, ''));
        }
    }

    this.selectView = function(view)
    {
        // extract view from class
        this.currentView = view;
        this.rebuildView(this.currentView);

        $('#' + this.getId() + ' .view').attr('class', 'view ' + this.currentView);
        $('#' + this.getId() + ' .currentview p').css('background-image', 'url(' + CompanyCarAdviceTool.view_backgrounds[this.currentView] + ')');

        $('#' + this.getId() + ' .view-selector div').removeClass('selected');
        $('#' + this.getId() + ' .view-selector .' + this.currentView).addClass('selected');
    }

    this.rebuildView = function(view)
    {
        // unbind all previous events
        $('#' + this.getId() + ' .companycar .title a').unbind('click');
        $('#' + this.getId() + ' .companycar ol li').unbind('mouseover');

        // set html
        $('#' + this.getId() + ' .companycar').html(this.views[view]['html']);

        // bind new events
        for (var a in this.views[view]['coords']) {
            var li = $('#' + a);
            li.css({'left': this.views[view]['coords'][a][0], 'top': this.views[view]['coords'][a][1]});
        }

        $('#' + this.getId() + ' ol li').bind('mouseover', Delegate.create(this, this.bringToFront));
        $('#' + this.getId() + ' .companycar .title a').bind('click', Delegate.create(this, this.clickHandler));

        // this one is for IE6
        if ($.browser.msie && (Number($.browser.version) < 7)) {
            $('#' + this.getId() + ' ol li').hover(
            function()
            {
                $(this).find('.box').css('display', 'block');
            },
            function()
            {
                $(this).find('.box').css('display', 'none');
            }
            );
        }

        // set new styles
        for (var a in this.views[view]['styles']) {
            $('#' + a + ' .title a').css('background-image', 'url(' + this.views[view]['styles'][a] + ')');
        }
    }

    this.rebuildBreadcrumbs = function(breadcrumbs)
    {
        var obj = $('#' + this.getId() + ' .breadcrumbs');

        // unbind all previous events
        obj.find('a').unbind('click');

        // compose html
        var crumbs = '<ul>';
        var prefix = '/';
        var first = true;
        for (var a in breadcrumbs) {
            prefix += a + '/';
            crumbs += '<li' + (first ? ' class="firstcrumb"' : '') + '><a href="' + prefix + '" title="' + breadcrumbs[a].title + '">' + breadcrumbs[a].title + '</a></li>';
            first = false;
        }

        crumbs += '</ul>';

        obj.html(crumbs);

        obj.find('a').bind('click', Delegate.create(this, this.clickHandler));
    }

    this.bringToFront = function(e)
    {
        if (!e) e = windows.event;
        if (e) {
            var target = getTarget(e);

            if (target.nodeName.toLowerCase() != 'li') {

                // bubble up to <li> node
                target = $(target).parents('li');

            } else {
                target = $(target);
            }

            $(target).css('z-index', this.getNextHighestIndex());
        }
    }

    this.getNextHighestIndex = function()
    {
        return ++CompanyCarAdviceTool.zIndexCount;
    }

    CompanyCarAdviceTool.instances[this.getId()] = this;
}

CompanyCarAdviceTool.findById = function(id)
{
    for (var a in CompanyCarAdviceTool.instances) {
        if (a === id) {
            return CompanyCarAdviceTool.instances[a];
        }
    }
    return false;
}

CompanyCarAdviceTool.COUNTER = 0;
CompanyCarAdviceTool.instances = {};
CompanyCarAdviceTool.zIndexCount = 10;
CompanyCarAdviceTool.view_backgrounds = {};
CompanyCarAdviceTool.infoUrlPart = '';


/**
 * Dataprovider class. Handles the fetching of contents by loading url's.
 *
 * @author Peter Kruithof
 */
function DataProvider()
{
    // constants for the modal
    this.LOADING = 'loading';
    this.IDLE = 'idle';
    this.ERROR = 'err';

    this.lastResult = null;
    this.currentSection = null;
    this.state = null;
    this.loadingIcon = null;
    this.listeners = {};
    this.timeoutID = null;
    this.structure = {};

    this.getUrlPartsFromPath = function(path)
    {
        path = path.replace(/^\//, '');
        path = path.replace(/\/$/, '');
        return path.split('/');
    }

    this.getBreadCrumbsFromPath = function(path)
    {
        var urlparts = this.getUrlPartsFromPath(path);
        var breadcrumbs = {};

        var section = this.structure;
        for (var i = 0, j = urlparts.length; i < j; i++) {

            if (!(urlparts[i] in section)) break;
            section = section[urlparts[i]];
            breadcrumbs[urlparts[i]] = {'title' : section.title, 'menutitle' : section.menutitle};
        }

        return breadcrumbs;
    }

    this.setState = function(state)
    {
        this.state = state;
        this.dispatchEvent('state');
    }

    this.setTimeout = function(miliseconds)
    {
        this.clearTimeout();

        var self = this;
        this.timeoutID = setTimeout(function() { self.timeout(); }, miliseconds);
    }

    this.clearTimeout = function()
    {
        if (this.timeoutID) {
            clearTimeout(this.timeoutID);
        }
    }

    this.timeout = function()
    {
        this.setState(this.ERROR);
//        Modal.display(getText('TimeoutError'), 'error');
    }

    /**
     * Registers an event listener for this class.
     *
     * @param {String}      event   The event to listen to.
     * @param {Function}    func    The function to call when event is broadcasted.
     * @param {Object}      scope   The scope to preserve while applying the callback.
     */
    this.addEventListener = function(event, func, scope)
    {
        if (!this.listeners[event]) this.listeners[event] = [];

        for (var i = 0; i < this.listeners[event].length; i++) {
            if (this.listeners[event][i].callback === func) return;
        }
        this.listeners[event].push({'callback' : func, 'scope' : scope});
    }

    /**
     * Dispatches an event to all registered listeners.
     *
     * @param {String} event The event to dispatch
     */
    this.dispatchEvent = function(event)
    {
        if (this.listeners[event] && (this.listeners[event].length > 0)) {
            for (var i = 0; i < this.listeners[event].length; i++) {
                this.listeners[event][i].callback.call(this.listeners['update'][i].scope);
            }
        }
    }

    /**
     * Executes an XmlHttpRequest, and delegates the returned JSON result to {@link parseResult}
     */
    this.fetch = function(uri)
    {
        if (!uri) throw new Error(';DataProvider.fetch : argument \'uri\' missing or invalid');

        // set timer for possible timeout
        this.setTimeout(30000); // 30 seconds should be more than enough

        this.setState(this.LOADING);
        $.getJSON(uri, Delegate.create(this, this.parseResult));
    }

    /**
     * Event handler called from {@link fetch}.
     * Adds all new points and children and dispatches an update event.
     *
     * @param {Object} result The result object returned by the JSON request
     */
    this.parseResult = function(result)
    {
        this.clearTimeout();

        this.setState(this.IDLE);

        // everything ok?
        if (result && !result.isError) {

            // store the result
            this.lastResult = result;

            // parse the result
            if (result.page_data) {

                // get urlparts
                var urlparts = this.getUrlPartsFromPath(result.page_data.path) || '';

                // update structure
                this.structure = this.updateStructure(this.structure, urlparts, result.page_data);
            }

            // let listeners know we've been updated
            this.dispatchEvent('update');

        } else {

            // TODO something went wrong, display something on screen?
            throw new Error('Invalid result returned.');
        }
    }

    this.updateStructure = function(structure, urlparts, page_data)
    {
        if (urlparts.length > 0) {
            var urlpart = urlparts.shift();

            if (!(urlpart in structure)) {
                structure[urlpart] = {};
            }

            if (urlparts.length > 0) {
                structure[urlpart] = this.updateStructure(structure[urlpart], urlparts, page_data);
            } else {
                structure[urlpart] = page_data;
            }
        }

        return structure;

    }

    this.getSection = function(path)
    {
        // get urlparts
        var urlparts = this.getUrlPartsFromPath(path);

        if (urlparts.length > 0) {
            var section = this.structure;
            for (var i = 0, j = urlparts.length; i < j; i++) {

                if (!(urlparts[i] in section)) return false;

                section = section[urlparts[i]];
            }

            return section;
        }

        return false;
    }
}