// MTC buurt issue tracker functionality

var throbber;
// application initialization
document.observe('dom:loaded', function() 
{
    if ($('buurtmap')) {
        new BuurtTracker('buurtmap', 'buurtapp');
        // application cleanup
        Event.observe(window, 'unload', function() {GUnload();});
    }
    if ($('profileform') || $('removeform'))
        new Profile();
    if ($('logoutlink') || $('login'))
        new Authentication();
});

// predefined icons
var icons = {
    red:      {primaryColor: '#FF0000', cornerColor: '#FFCCCC', strokeColor: '#EE0000'},
    yellow:   {primaryColor: '#DDCC00', cornerColor: '#FFFFFF', strokeColor: '#DDBB00'},
    green:    {primaryColor: '#00EE00', cornerColor: '#CCFFCC', strokeColor: '#00DD00'},
    darkgrey: {primaryColor: '#666666', cornerColor: '#CCCCCC', strokeColor: '#555555'},
    blue:     {primaryColor: '#4444FF', cornerColor: '#CCCCFF', strokeColor: '#3333EE'}
};

// issue tracker interface
var BuurtTracker = Class.create({

    initialize: function(mapId, appId)
    {
        throbber = $('throbber');
        throbber.show();
        this.mapId = mapId;
        this.appId = appId;
        // URL of app
        this.url = window.location.protocol + '//' + window.location.host + '/ajaxclient.php';
        // set up the map
        if ($(this.mapId))
            new DTCMap(this.appId, this.mapId);
        // global event handlers
        $$('.register').each(function(a) {a.observe('click', this.registerForm.bindAsEventListener(this))}, this);
        // decide which content to display based on anchor at page load
        switch (window.location.hash) {
            case '#register':
                this.registerForm();
                break;
            case '#report':
                this.reportForm();
                break;
            default:
                this.showInfo(window.location.hash);
                break;
        }
//        throbber.hide();
    },

    // get the registration form
    registerForm: function(e)
    {
        new Registration(this.appId);
        if (e) // may not have been called as an event handler
            Event.stop(e);
    },

    // show info triggered by anchor
    showInfo: function(hash)
    {
        $$('div.info').each(function (d) {d.hide()});
        var id = hash.substr(1);
        if ($(id)) {
            var info = $(id).cloneNode(true).show();
            $(this.appId).insert({top: info});
        }
    }

});


// map handler
var DTCMap = Class.create({

    initialize: function(appId, mapId)
    {
        this.pane = $(appId);
        $$('.report').each(function(a) {a.observe('click', this.showReport.bindAsEventListener(this, 0))}, this);
        // URL of app
        this.url = window.location.protocol + '//' + window.location.host + '/ajaxclient.php';
        
        var copyOSM = new GCopyrightCollection('<a href="http://www.openstreetmap.org/">OpenStreetMap</a>');
        copyOSM.addCopyright(new GCopyright(1, new GLatLngBounds(new GLatLng(-90, -180), new GLatLng(90, 180)), 0, ' '));
        var tilesMapnik = new GTileLayer(copyOSM, 12, 18, {tileUrlTemplate: 'http://tile.openstreetmap.org/{Z}/{X}/{Y}.png'});
        var mapMapnik = new GMapType([tilesMapnik], G_NORMAL_MAP.getProjection(), 'kaart');
//        this.map = new GMap2($(mapId), {mapTypes: [mapMapnik]});
        this.map = new GMap2($(mapId), {mapTypes: [mapMapnik, G_HYBRID_MAP]});
        this.map.addControl(new GMapTypeControl());
        this.map.addControl(new GLargeMapControl());
        this.map.enableScrollWheelZoom();
        this.map.setCenter(new GLatLng(parseFloat($F('maplat')), parseFloat($F('maplng'))), parseInt($F('mapzoom')));
        GEvent.addListener(this.map, 'moveend', this.updateMap.bindAsEventListener(this));
        // store report ids to track inclusion
        this.reports = new Array();
        // fire event to trigger marker fetch
        GEvent.trigger(this.map, 'moveend');
    },

    // update map after scrolling or zooming
    updateMap: function(e)
    {
        throbber.show();
        // update map data by sending current properties
        // also serves to store map state in the session
        var zoom = this.map.getZoom();
        var center = this.map.getCenter();
        var bounds = this.map.getBounds();
        new Ajax.Request(this.url, {
            parameters: {
                'updatemap': true,
                'zoom': zoom,
                'lng': center.lng(),
                'lat': center.lat(),
                'north': bounds.getNorthEast().lat(),
                'east': bounds.getNorthEast().lng(),
                'south': bounds.getSouthWest().lat(),
                'west': bounds.getSouthWest().lng()
            },
            onComplete: function(t) 
            {
                if (t.responseJSON.reports) {
                    t.responseJSON.reports.each(function (r)
                    {
                        if (!this.reports[r.rid]) {
                            // add a marker for each report
                            // FIXME: investigate rounding error in parseFloat
                            var point = new GLatLng(parseFloat(r.lat), parseFloat(r.lng));
                            this.reports[r.rid] = new GMarker(point, {
                                icon: MapIconMaker.createMarkerIcon(eval('icons.' + r.icon)),
                                title: r.summary,
                                clickable: true
                            });
                            // FIXME: add a click event to show info
                            GEvent.addListener(this.reports[r.rid], 'click', this.showReport.bindAsEventListener(this, r.rid));
                            this.map.addOverlay(this.reports[r.rid]);
                        }
                    }, this);
                }
                throbber.hide();
            }.bind(this)
        });
    },
    
    showReport: function(e, rid)
    {
        new Ajax.Updater(this.pane, this.url, {
            parameters: {viewreport: true, rid: rid},
            onCreate: function() {$('throbber').show()},
            onComplete: this.setupReport.bind(this, rid)
        });
    },
    
    saveReport: function(e)
    {
        new Ajax.Updater(this.pane, this.url, {
            parameters: $('reportform').serialize(),
            onCreate: function() {$('throbber').show()},
            onComplete: this.setupReport.bind(this, parseInt($F('rid')))
        });
        Event.stop(e);
    },
    
    confirmReport: function(e)
    {
        var elm = Event.element(e);
        new Ajax.Updater(this.pane, this.url, {
            parameters: {confirmreport: true, rid: elm.id},
            onCreate: function() {$('throbber').show()},
            onComplete: this.setupReport.bind(this, elm.id)
        });
        Event.stop(e);
    },
    
    // set up report form handlers
    setupReport: function(rid)
    {
        // unhide marker in case it's no longer active
        if (this.activeReport && this.reports[this.activeReport].isHidden())
            this.reports[this.activeReport].show();
        if ($('reportform') && this.activeReport == rid) { // move marker to locator if form and report exist
            if (rid && this.locator)
                this.reports[this.activeReport].setLatLng(this.locator.getLatLng());
        }
        this.activeReport = rid;
        // add draggable locator if we have a form
        if ($('reportform')) {
            var loc;
            // place locator in location of marker if the report exists
            if (this.activeReport) {
                this.reports[this.activeReport].hide();
                loc = this.reports[this.activeReport].getLatLng();
            }
            else { // otherwize put it in the center of the map
                var loc = this.map.getCenter();
                var lat = loc.lat();
                var lng = loc.lng();
                $$('.maplat').each(function(l) {l.value = lat});
                $$('.maplng').each(function(l) {l.value = lng});
            }
            if (this.locator) { // move locator if it exists
                this.locator.setLatLng(loc);
                if (this.locator.isHidden())
                    this.locator.show();
            }
            else { // or create a new locator
                this.locator = new GMarker(loc, {
                    icon: MapIconMaker.createMarkerIcon(icons.red),
                    title: 'sleep om te verplaatsen',
                    clickable: false,
                    draggable: true,
                    bouncy: true
                });
                GEvent.addListener(this.locator, 'dragend', this.updateLocation);
                this.map.addOverlay(this.locator);
            }
            $('reportform').observe('submit', this.saveReport.bindAsEventListener(this));
        }
        // remove locator since it's a noneditable report
        else if (this.locator)
            this.locator.hide();
        
        $$('.report').each(function(a) {a.observe('click', this.showReport.bindAsEventListener(this, 0))}, this);
        $$('.confirm').each(function(a) {a.observe('click', this.confirmReport.bindAsEventListener(this))}, this);
        throbber.hide();
    },
    
    // update marker location coordinates
    updateLocation: function(loc)
    {
        var lat = loc.lat();
        var lng = loc.lng();
        $$('.maplat').each(function(l) {l.value = lat});
        $$('.maplng').each(function(l) {l.value = lng});
    }

});

// registration form and input handling
var Registration = Class.create({

    initialize: function(appId)
    {
        throbber.show();
        this.appId = appId;
        // URL of app
        this.url = window.location.protocol + '//' + window.location.host + '/ajaxclient.php';
        new Ajax.Updater(this.appId, this.url, {
            method: 'get',
            parameters: { view: 'register'},
            onComplete: this.setupRegistration.bind(this)
        });

    },

    // add event handlers for registration form
    setupRegistration: function(t)
    {
        this.errorLine = $('registererror');
        $('registerform').observe('submit', this.validate.bindAsEventListener(this));
        throbber.hide();
    },

    // validate form input, block on incomplete
    // perform registration request if valid
    validate: function(e)
    {
        var elm = Event.element(e);
        var email = $F('email');
        var pass1 = $F('pass1');
        var pass2 = $F('pass2');
        // check for missing fields
        if (elm.select('label input').find(function(i) {return i.value == ''})) {
            this.errorLine.update('Vul a.u.b. alle velden in.');
            this.errorLine.show();
        }
        // trivial check for invalid email
        else if (email.match(/[\w.-]+@[\w.*]+\.[a-zA-Z]{2,}/) == null) {
            this.errorLine.update('Vul a.u.b. een email adres in.');
            this.errorLine.show();
        }
        // check if passwords are equal
        else if (pass1 != pass2) {
            this.errorLine.update('De wachtwoorden zijn niet identiek.');
            this.errorLine.show();
            $('pass1').clear();
            $('pass2').clear();
        }
        // check if password is long enough
        else if ($F('pass1').length < 6) {
            this.errorLine.update('Het wachtwoord is te kort.');
            this.errorLine.show();
            $('pass1').clear();
            $('pass2').clear();
        }
        else {
            this.errorLine.update();
            this.errorLine.hide();
            new Ajax.Request(this.url, {
                parameters: elm.serialize(true),
                onSuccess: this.processRegistration.bind(this)
            })
        }
        Event.stop(e);
    },

    // process registration response
    processRegistration: function(t)
    {
        if (t.responseJSON.success) {
            // successful registration, reload page
            window.location.href = window.location.protocol + '//' + window.location.host + '/index.php#registered';
        }
        else {
            // account already exists
            this.errorLine.update('Er bestaat al een account met dit email adres.');
            this.errorLine.show();
        }
    }

});

// profile and account removal form handling
var Profile = Class.create({
    initialize: function()
    {
        // URL of app
        this.url = window.location.protocol + '//' + window.location.host + '/ajaxclient.php';
        this.errorLine = $('profileerror');
        this.statusLine = $('profilestatus');
        this.profile = $('profileform');
        if (this.profile)
            this.profile.observe('submit', this.saveAccount.bindAsEventListener(this));
        this.remove = $('removeform');
        if (this.remove)
            this.remove.observe('submit', this.removeAccount.bindAsEventListener(this));
    },

    saveAccount: function(e) 
    {
        var elm = Event.element(e);
        var email = $F('email');
        // trivial check for invalid email
        if (email.match(/[\w.-]+@[\w.*]+\.[a-zA-Z]{2,}/) == null) {
            this.errorLine.update('Vul a.u.b. een email adres in.');
            this.errorLine.show();
        }
        else {
            this.errorLine.update();
            this.errorLine.hide();
            new Ajax.Request(this.url, {
                parameters: elm.serialize(true),
                onSuccess: function(t) 
                {
                    if (parseInt(t.responseJSON.exists) > 0) {
                        // account already exists
                        this.errorLine.update('Een andere account gebruikt het ingevoerde email adres al. Het email adres is ongewijzigd.');
                        this.errorLine.show();
                    }
                    else {
                        this.statusLine.update('De wijzigingen zijn opgeslagen.');
                        this.statusLine.show();
                        Element.hide.delay(3, this.statusLine);
                    }
                }.bind(this)
            })
        }
        Event.stop(e);
    },

    removeAccount: function (e) 
    {
        elm = Event.element(e);
        if (confirm('Wilt u uw account opheffen?')) {
            new Ajax.Request(this.url, {
                parameters: elm.serialize(true),
                onSuccess: function(t) 
                {
                    if (t.responseJSON.removed) {
                        window.location.href = window.location.protocol + '//' + window.location.host + '/index.php#removed';
                    }
                }
            })
        }
        Event.stop(e);
    }
});

// authentication functionality
var Authentication = Class.create({
    initialize: function()
    {
        // URL of app
        this.url = window.location.protocol + '//' + window.location.host + '/ajaxclient.php';
        this.errorLine = $('autherror');
        this.login = $('login');
        if (this.login)
            this.login.observe('submit', this.authenticate.bindAsEventListener(this));
        this.logout = $('logoutlink');
        if (this.logout)
            this.logout.observe('click', this.bye.bindAsEventListener(this));
    },

    authenticate: function(e) 
    {
        var elm = Event.element(e);
        this.errorLine.update();
        this.errorLine.hide();
        new Ajax.Request(this.url, {
            parameters: elm.serialize(true),
            onSuccess: function(t) 
            {
                if (t.responseJSON.loggedin) {
                    window.location.href = window.location.protocol + '//' + window.location.host + '/index.php';
                }
                else {
                    this.errorLine.update('Aanmelden mislukt.');
                    this.errorLine.show();
                    Element.hide.delay(3, this.errorLine);
                }
            }.bind(this)
        });
        Event.stop(e);
    },

    // logout
    bye: function (e) 
    {
        new Ajax.Request(this.url, {
            parameters: {auth_submit: true, logout: true, noclear: true},
            onSuccess: function(t) 
            {
                if (!t.responseJSON.loggedin) {
                    window.location.href = window.location.protocol + '//' + window.location.host + '/index.php';
                }
            }
        })
        Event.stop(e);
    }
});

