// Maui - Mootools Application User Interface
// a JavaScript UI framework, built on Mootools
// www.mauiframework.com
//
// Copyright (c) 2007-2010 Shawn Van Ittersum and MultiWidget LLC.  All rights reserved.
//
// Requires Mootools 1.11

// Extend Mootools Class to allow static properties and methods.
var MootoolsClass = Class;
var Class = function(properties) {
  if (statik = properties['Static']) {
    delete properties['Static'];
  }
  klass = new MootoolsClass(properties);
  if (statik) {
    klass = $extend(klass,statik);
  }
  return klass;
};

// Implement additional methods on Element class
Element.extend({
  setClass: function(klass, bool) {
    this[bool ? 'addClass' : 'removeClass'](klass);
  }
});

// Maui singleton object for each JS window.
var Maui = {
  tabSets: {},
  
  start: function (e) {
    this.discoverTabSets();
  },
  
  addCallbacks: function (callbacks) {
    window.addEvents(callbacks);
  },
  
  discoverTabSets: function () {
    var tabs = $$('.tab');
    
    tabs.each( function(el) {
      var parts = el.id.split('.');
      var tab_set_name = parts[0];
      var tab_name = parts[1];
      
      if (!this.tabSets[tab_set_name]) {
        this.tabSets[tab_set_name] = new MauiTabSet(tab_set_name);
      }
      tab_set = this.tabSets[tab_set_name];
      
      tab_set.addTab(el);
      if (el.hasClass('selected')) {
        tab_set.selectTab(el);
      }
    }.bind(this));
  },
  
	popup: function (msg) {
		var w = window.open("about:blank");
		w.document.open();
		w.document.writeln(msg);
		w.document.close();
	}
};

var MauiTabSet = new Class({
  name: null,
  selectedTabName: null,
  
  initialize: function(name) {
    this.name = name
  },
  addTab: function(el) {
    el = $(el);
    el.href = '#';
    el.addEvent('click', this.clickTab.bind(this));
  },
  clickTab: function(e) {
    e = new Event(e).stop();
    this.selectTab(e.target);
  },
  selectTab: function(el) {
    el = $(el);
    
    if (this.selectedTabName) {
      $([this.name,this.selectedTabName,'tab'].join('.')).removeClass('selected');
      $([this.name,this.selectedTabName,'pane'].join('.')).removeClass('selected');
    }
    
    this.selectedTabName = el.id.split('.')[1];
    $([this.name,this.selectedTabName,'tab'].join('.')).addClass('selected');
    $([this.name,this.selectedTabName,'pane'].join('.')).addClass('selected');
  }
});

var MauiAjax = new Class({
  Static: {
    // static class properties and methods
    last: null,
  
    showLast: function () {
    	if (!this.last) {
    		alert('No AJAX calls have been made.');
    	} else {
    	  this.last.show();
      }
    }
  },
  
  // instance properties and methods
	url: null,
	
	initialize: function (url,options) {
	  this.ajax = new Ajax(this.url = url, options);
	  this.constructor.last = this;
		this.ajax.request();
	},
	show: function () {
		var response_text = this.ajax.response ?
		  this.last_request.response.text : '';
	  
		Maui.popup(
		  '<b>URL:</b><br>' + this.last_url +
		  '<br><br><b>Response (Rendered):</b><br><div style="border: 1px solid #f93; background-color: #fe9; padding: 4px;">' +
		  response_text + '</div><br><br><b>Response (Source):</b><br><pre>' + response_text.replace(/</g,'&lt;') + '</pre>'
		);
	}
});

var MauiAutocompleteItemsPreloader = new Class({
  initialize: function(url) {
    var ajax = new Kiss.Ajax();
    ajax.request(url, {
      method: 'get',
      onSuccess: function(response) {
        this.setItems(eval(response));
      }.bind(this)
    });
  },
  getItems: function() {
    return this.items;
  },
  setItems: function(items) {
    this.items = items;
  }
});

var MauiAutocomplete = new Class({
  options: {
    maxCompletions: 10,
    idPrefix: '',
    items: null,
    itemsPreloader: null
  },
  initialize: function(input_element,options) {
    this.setOptions(options);

    this.input_element = input_element;
    this.completions_element = new Element('div',{
      'id': this.options.idPrefix + input_element.name + '_completions',
      'class': 'completions'
    });
    this.completions_element.injectAfter(this.input_element);
    
    var ac = this;
    this.input_element.onkeydown = (function(e) {
      var event = new Event(e);
      if (event.key === 'down') {
        if (ac.selected_index < ac.completions.length - 1) {
          ac.select_index(ac.selected_index + 1);
        } else if (!ac.selected_index) {
          ac.select_index(0);
        }
      } else if (event.key === 'up') {
        if (ac.selected_index > 0) {
          ac.select_index(ac.selected_index - 1);
        } else {
          ac.deselect();
        }
      } else if (event.key === 'enter') {
        if (this.selected_id != undefined) {
          return this.onChoose();
        } else {
          return true;
        }
      } else if (event.key === 'tab') {
        if (this.selected_id != undefined) {
          this.onChoose();
        }
        this.hide();
        return true;
      } else {
        setTimeout( function() {
          ac.autocomplete(ac.input_element.value);
        },10);
      }
      return true;
    }).bind(this);
  },
  autocomplete: function(value) {
    if (this.autocomplete_timeout) {
      clearTimeout(this.autocomplete_timeout);
    }
    value = value.replace(/^\s+/,'').replace(/\s+$/,'')
    if (value === '') {
      this.hide();
      return;
    }
    
    if (!this.options.items) {
      if (this.options.itemsPreloader) {
        this.options.items = this.options.itemsPreloader.getItems() || null;
        if (!this.options.items) {
          // still have no items; try again in 0.5 sec
          this.completions_element.innerHTML = "Loading...";
          this.show();
      
          var obj = this;
          this.autocomplete_timeout = setTimeout(
            function() {
              obj.autocomplete(value);
            }, 500
          );
          return;
        }
      } else {
        this.completions_element.innerHTML = "Missing data for completions";
        this.show();
        return;
      }
    }

    var matched_name;
    var completions = [];
    var num_completions = 0;
    var list = this.options.items;
    var num_regexps_matched;

    var regexps = [];
    values = value.split(/\s+/);
    for (i=0; i < values.length; i++) {
      regexps.push( new RegExp('\\b(' + values[i] + ')', 'i') );
    }
    
    var item;
    for (i=0; i < list.length; i++) {
      item = list[i];

      num_regexps_matched = 0;
      match_name = item.name;
      display_name = item.name;

      for (j=0; j < regexps.length; j++) {
        regexp = regexps[j];
        if (match_name.match(regexp)) {
          num_regexps_matched++;
          match_name = match_name.replace(regexp,'_');
          display_name = display_name.replace(regexp,'<em>$1</em>');
        }
      }

      if (num_regexps_matched === regexps.length) {
        completions.push({
          id: item.id,
          name: item.name,
          display_name: display_name,
          context: item.context
        });
        num_completions++;
        if (num_completions === this.options.maxCompletions) {
          break;
        }
      }
    }

    this.completions = completions;

    if (this.completions.length === 0) {
      this.hide();
      if (this.options.idElement) {
        this.options.idElement.value = '';
      }
    } else {
      var html = '';
      var i = 0;
      completions.each( function (c) {
        html += '<div class="item" id="ac_' + (i++) + '">' + c.display_name + '<div class="context">' + c.context + '</div></div>';
      });
      
      this.completions_element.innerHTML = html;
      
      ac = this;
      item_hover = function() {
        ac.select_item(this);
      }
      item_click = function() {
        ac.select_item(this);
        ac.onChoose()
      }
      $$('#' + this.completions_element.id + ' .item').each( function(item) {
        item.onmouseover = item_hover;
        item.onclick = item_click;
      });

      this.select_index(0);
      this.show();
    }
  },
  selected_name: function() {
    return (this.selected_index != undefined) ? this.completions[this.selected_index].name : '';
  },
  deselect: function () {
    if (this.selected_index != undefined) {
      if (el = $('ac_' + this.selected_index)) {
        el.removeClass('selected');
      }
    }
    this.selected_index = undefined;
    this.selected_id = undefined;
  },
  select_item: function(el) {
    this.select_index(el.id.substring(3));
  },
  select_index: function(index) {
    this.deselect();
    this.selected_index = index;
    this.selected_id = this.completions[index].id;
    this.hilite_selected();
    
    if (this.options.idElement) {
      this.options.idElement.value = this.selected_id || '';
    }
  },
  hilite_selected: function(id) {
    var el = $('ac_' + this.selected_index);
    if (!el) {
      this.deselect();
    } else {
      el.addClass('selected');
    }
  },
  hide: function() {
    this.deselect();
    this.completions_element.innerHTML = '';
    this.completions_element.style.display = 'none';
  },
  show: function() {
    this.completions_element.style.display = 'block';
  },

  onChoose: function() {
    this.input_element.value = this.selected_name();
    if (this.options.onChoose) {
      this.options.onChoose.bind(this)();
    }
    this.hide();
    return false;
  }
});
MauiAutocomplete.implement(new Options);

// Start Maui after DOM ready.
window.addEvent('domready',function() { Maui.start() });
