//
// We instantiate an instance of this class to handle the address lists
//

var Addresses = Class.create();
Addresses.prototype = {

    initialize: function (advanced,fmdomain) {
        // Handle create form submission with create()
        $('create').observe ('submit', this.create.bindAsEventListener (this));

        // Handle search form submission with search()
        $('search').observe ('submit', this.search.bindAsEventListener (this));

        // Handle clicks on items in the lists with handle()
        $('independent_list', 'valid_list', 'inactive_list').compact().invoke ('observe', 'click', this.handle.bindAsEventListener (this));

        // FIXME: use these values to select an optimized (no conditional) render routine
        this.advanced = advanced;
        this.fmdomain = fmdomain;

        // Handle notify form submission with notify()
        if (fmdomain) $('fmnotify').observe ('submit', this.fmnotify.bindAsEventListener (this));

        // Start out with three empty lists
        this.lists = {independent: $A(), valid: $A(), inactive: $A()};

        var domain_address_count = new Number ($('domain_address_count').innerHTML);

        if (domain_address_count < 250) {

            // Get a reference to the form
            var form = $('search');
         
            // Get our parameters
            var parameters = Form.serialize (form, true);
         
            // Call the routine to get our data
            new Ajax.Request ('list',
                              {method: 'get',
                               onFailure: function () {
                                   alert ('Failed to retrieve list');
                               },
                               onSuccess: this.loadData.bind (this),
                               parameters: parameters});
            // Kick off a request to get our data
//            new Ajax.Request ('list', {method: 'get',
//                                       onFailure: function () {
//                                           alert ('Failed to retrieve list');
//                                       },
//                                       onSuccess: this.loadData.bind (this)});
        } else {
            $('address_lists').hide ();
            if ($('independent_list')) {
                $('independent_list').hide ();
            }
            if ($('valid_list')) {
                $('valid_list').hide ();
            }
            if ($('inactive_list')) {
                $('inactive_list').hide ();
            }
        }
    },

    addEntries: function (entries) {

        // Iterate over each entry to add
        $A(entries).each (function (e) {

            // Override the toString function for sorting and binary searching
            e.toString = function () { return this.uid };

            // Look for the position of this in the appropriate list
            var pos = this.lists[e.type].binarySearch (e);

            // The item isn't already in the list
            if (pos < 0) {

                // This is where it's going to go
                var newpos = Math.abs (pos) - 1;

                // Look for an existing item at that point (that will be after it on insert)
                var after = this.lists[e.type][newpos];

                // If there's something following it
                if (after)

                    // Insert before that now-following item
                    new Insertion.Before ($(after.uid).up ('tr'), this.render (e));
                    // $(after.uid).insert ({before: this.render (e)})
                else

                    // Add to the end of the list
                    new Insertion.Bottom ($(e.type + '_list'), this.render (e));
                    // $(e.type + '_list').insert (this.render (e));

                // Insert the new item in the model list
                this.lists[e.type].splice (newpos, 0, e);

                $('address_lists').show ();
                if ($(e.type + '_list')) {
                    $(e.type + '_list').show ();
                }

                // Update the count
                var count = new Number ($(e.type + '_count').innerHTML);
                $(e.type + '_count').update (++count);
            }
        }.bind (this));
    },

    create: function (e) {

        // Don't propogate
        Event.stop (e);

        // What element fired?
        var element = Event.element(e);

        // Get a reference to the form
        var form = element.tagName == "FORM" ? element : element.form;

        // Get our parameters
        var parameters = Form.serialize (form, true);

        // Disable the form
        Form.disable (form);

        // Call the routine to create the routines
        new Ajax.Request ('create',
                          {onComplete: function (form) {
                              Form.enable (form);
                              Form.reset (form);
                           }.bind (this, form),
                           onFailure: function () {
                               alert ('Could not add addresses');
                           },
                           onSuccess: function (response) {
                               this.addEntries (response.responseText.evalJSON (true));
                           }.bind (this),
                           parameters: parameters});
    },

    handle: function (e) {

        // A reference to the initiating element
        var el = Event.element (e);

        // We're only handling buttons here
        if (el.tagName.toLowerCase() == 'input') {

            // Don't propogate
            Event.stop (e);

            // Get the new destination & action
            var dest = el.readAttribute ('name');
            var action = el.readAttribute ('value');

            // Get the form and the table row
            var form = el.form;
            var row = Event.findElement(e,"tr");

            // Get the address to be acted on and the timestamp
            var address = form.id.gsub('%22', '"');
            var timestamp = form.title;

            // Disable the form
            Form.disable (form);

            // Call the routine to reclassify the address
            new Ajax.Request ('reclassify/' + action.toLowerCase(),
                              {onFailure: function () {
                                  alert ('Could not remove entry');
                               },
                               onSuccess: function (dest, row, address, timestamp) {

                                   // Get the list it's currently on
                                   var current = row.up ('table').id.replace (/_list$/, '');

                                   // Get the list of who manages the address
                                   var managed = '';
                                   if (this.fmdomain) {
                                       managed = row.down ('td', 4).down ('a').innerHTML;
                                   } else {
                                       managed = row.down ('td', 3).down ('a').innerHTML;
                                   }

                                   // Set the notify state according to what the address is now
                                   var prestate = '';
                                   var poststate = '';
                                   var state = row.down('strong');
                                   if (state) {
                                       prestate = '<strong>';
                                       poststate = '</strong>';
                                   }

                                   // Remove the row
                                   row.remove();

                                   // Update the count on the current list
                                   var count = new Number ($(current + '_count').innerHTML);
                                   $(current + '_count').update (--count);

                                   if (count == 0) {
                                       $(current + '_list').hide ();
                                   }

                                   // console.log ("searching");

                                   // Find the address in the list
                                   var pos = this.lists[current].binarySearch (address);

                                   // console.log ("done searching");

                                   // If it's present, remove it
                                   if (pos >= 0)
                                       this.lists[current].splice (pos, 1);

                                   // console.log ("done splicing");

                                   // If we're not making it invalid
                                   if (dest != "invalid")

                                       // Add it to the new list
                                       this.addEntries ([{uid: address, createtimestamp: timestamp, type: dest, asclass: current, status1: prestate, status2: poststate, admins: managed}]);
                               }.bind (this, dest, row, address, timestamp),
                               parameters : {address: address}});
        }
    },

    loadData: function (response) {
        // console.time ('partitioning records');
        $A(response.responseText.evalJSON (true)).each (function (e) {

            // This allows us to sort quickly on IE and use canned binary search
            e.toString = function () { return this.uid.toLowerCase() };
            this.lists[e.type].push (e);
        }.bind (this));
        // console.timeEnd ('partitioning records');

        // console.time ('sorting records');
        $H(this.lists).each (function (l) {
            l.value.sort();
        });
        // console.timeEnd ('sorting records');

        $('address_lists').show ();

        this.renderLists ();
    },

    fmnotify: function (e) {

        // Don't propogate
        Event.stop (e);

        // What element fired?
        var element = Event.element(e);

        // Get a reference to the form
        var form = element.tagName == "FORM" ? element : element.form;

        // Get our parameters
        var parameters = Form.serialize (form, true);

        // Disable the form
        Form.disable (form);

        // Call the routine to notify the addresses
        new Ajax.Request ('fmnotify',
                          {onComplete: function (form) {
                              Form.enable (form);
                              Form.reset (form);
                           }.bind (this, form),
                           onFailure: function () {
                               alert ('Could not notify addresses');
                           },
                           onSuccess: function (response) {
                               alert (response.responseText);
                           },
                           parameters: parameters});
    },

    renderLists: function () {

        $H(this.lists).each (function (l) {
//            if (l.value.size() <= 0) return;

            // console.time ('Rendering content for ' + l.key);

            var contents = l.value.inject ($A(), function (a, e) { a.push (this.render (e)); return a; }.bind(this));

            var content = contents.join ('');

            if ($(l.key + '_list_body') && $(l.key + '_count')) {
                $(l.key + '_list_body').update (content);
                $(l.key + '_count').update (l.value.size());
            }

            if ($(l.key + '_list') && l.value.size() == 0) {
                $(l.key + '_list').hide ();
            } else if ($(l.key + '_list')) {
                $(l.key + '_list').show ();
            }
            // console.timeEnd ('Rendering content for ' + l.key);
        }.bind (this));
    },

    render: function (e) {
        var address = e.uid.gsub ('"', '%22');
        e.admins = e.admins || 'none';

        var bits = new Array('<tr><td><form id="', address, '" method="POST" title="', e.createtimestamp, '"><input name="invalid" type="button" value="Invalid" />');
        if (e.type == 'inactive') {
            if (e.asclass == 'valid')
                bits.push ('<input name="valid" type="button" value="Active" />')
            else
                bits.push ('<input name="independent" type="button" value="Active" />');
        }
        else {
            if (this.advanced) {
                if (e.type == 'valid')
                    bits.push ('<input name="independent" type="button" value="Independent" />')
                else
                    bits.push ('<input name="valid" type="button" value="Valid" />');
            }
            if (this.fmdomain) bits.push ('<input name="inactive" type="button" value="Inactive" />');
        }
        bits.push ('</form></td><td>' + e.status1 + '<a href="/address/' + address + '/sideline">' + e.uid.escapeHTML() + '</a>' + e.status2 + '</td>');
        bits.push ('<td><a href="/address/' + address + '/update">', e.createtimestamp, ' Z</a></td>');
        if (this.fmdomain) {
            bits.push ('<td>' + e.iphostnumber + '</td>');
        }
        if (e.asbackup && e.type != 'inactive') {
            bits.push ('<td>' + e.asbackup + '</td>');
        }
        bits.push ('<td><a href="/address/' + address + '/accounts">', e.admins, '</a></td>');
        if (this.fmdomain && e.userpassword) {
            bits.push ('<td>Password: <span style="font: 1.1em bolder monospace;">' + e.userpassword + '</span></td>');
        }
        bits.push ('</tr>');
        return bits.join('');
    },

    search: function (e) {

        // Don't propogate
        Event.stop (e);

        // What element fired?
        var element = Event.element(e);

        // Get a reference to the form
        var form = element.tagName == "FORM" ? element : element.form;

        // Get our parameters
        var parameters = Form.serialize (form, true);

        // Call the routine to get our data
        new Ajax.Request ('list',
                          {onFailure: function () {
                               alert ('Failed to retrieve list');
                           },
                           onSuccess: function (response) {
                               this.lists = {independent: $A(), valid: $A(), inactive: $A()};
                               this.loadData (response);
                           }.bind (this),
                           parameters: parameters});
    }
}
