/*
** Object CompoundCookie =======================================================
** Cookie compound value manager.
**
** Handles both "boolean" entries (foo&bar&baz&...) and key/value pairs (foo=1&bar=2&...) transparently
** Data is live, even when set through other sources... that is, the cookie is simply re-queried for each action ;)
**
** @param name : string cookie name
** @param cd   :  mixed compound delim (default '&')
** @param vd   :  mixed value delim (default '$')
** @return     : CompoundCookie instance
*/

var CompoundCookie = function(name, cd, vd) {
  
  cd = cd || '&';
  vd = vd || '$';
  
  // public method getData -----------------------------------------------------
  // @param type : string return type : 'string': stringified, 'flat': flat array (default: multidim array)
  // @return     : cookie data on success, null if no data
  var getData = this.getData = function(type) {
    var data = Cookie.read(name);
    if(!data) {
      return null;
    } else if(type === 'string') {
      return data;
    } else if(type === 'flat') {
      return data.split(cd);
    } else {
      return data.split(cd).map(function(item) { return item.split(vd); });
    }
  };
  
  // private method writeData --------------------------------------------------
  // Compiles the data array into a formatted string and writes the cookie
  // @param data : array cookie data
  // @return     : void
  var writeData = function(data) {
    data.map(function(item, index) {
      data[index] = item.join(vd);
    });
    data = data.join(cd);
    Cookie.write(name, data, { path: '/', duration: 365 });
  };
  
  // public method hasItem -----------------------------------------------------
  // @param item  : string item name
  // @param index : boolean, if true returns index of item if found (default: false)
  // @return      : boolean false if not found, boolean true if found and @param index == false, number index if found and @param index == true -- test identity if @param index == true!
  var hasItem = this.hasItem = function(item, index) {
    var data = getData();
    if(data) {
      for(var i = 0, l = data.length; i < l; ++i) {
        if(data[i][0] == item) {
          return index ? i : true;
        }
      }
    }
    return false;
  };
  
  // public method getItem -----------------------------------------------------
  // @param item : string item name
  // @return     : boolean false if not found, null if found but has no value, string value if found and has value
  this.getItem = function(item) {
    var data = getData();
    if(data) {
      for(var i = 0, l = data.length; i < l; ++i) {
        if(data[i][0] == item) {
          return data[i][1] || null;
        }
      }
    }
    return false;
  };
  
  // public method addItem -----------------------------------------------------
  // Safe to invoke without testing; will overwrite existing entry for item if present
  // @param item  : string item name
  // @param value : string value (optional)
  // @return      : void
  this.addItem = function(item, value) {
    var data  = getData() || [];
    var index = hasItem(item, true);
    if(index !== false && value) {
      data[index][1] = value;
    } else if(index === false && value) {
      data.push([item, value]);
    } else if(index === false) {
      data.push([item]);
    }
    writeData(data);
  };
  
  // public method removeItem --------------------------------------------------
  // @param item : string item name
  // @return     : void
  this.removeItem = function(item) {
    var data = getData();
    if(data) {
      for(var i = 0, l = data.length; i < l; ++i) {
        if(data[i][0] == item) {
          delete data[i];
          writeData(data.clean());
        }
      }
    }
  };
  
};



/*
** Function SectionLinks =======================================================
** Auto-generation of section links
*/

var SectionLinks = function(els) {
  
  els.each(function(el) {
    var id = el.id ? el.id : el.getParent('section') ? el.getParent('section').get('id') : null;
    if(!id) return;
    
    el.grab(new Element('a', { 'href': '#' + id, 'class': 'section', 'text': '¶', 'title': Ashe.text['section-link'][Ashe.LANG] }));
  });
  
  var tips = new Tips($$('a.section'), { className: 'section-tip', title: null, text: function(el) {
    return el.get('title');
  } });
  
};



/*
** Function AutoCollapsibles ===================================================
** Auto-generation of collapsible section in document-style pages.
**
** Requires the collapsible section to be enclosed by an element, preferably |section|.
** Injects the trigger into the passed in element.
** Requires html@data-page-id to be set and requires the passed in element (or its |section| parent) to have an @id set.
** Uses a cookie to remember state (relies on CompoundCookie object).
*/

var AutoCollapsibles = function(els) {
  
  var cookie = new CompoundCookie('collapsibles');
  var page   = $$('html')[0].get('data-page-id');
  
  // Function that takes care of the actual collapsing/expanding ---------------
  var toggle = function(el) {
    var group = el.getAllNext();
    var id    = el.id || el.getParent('section').get('id') || null;
    
    if(el.get('data-collapsible') == 'expanded') {
      group.hide();
      el.set('data-collapsible', 'collapsed');
      el.getElement('.collapsible').set('text', Ashe.text['collapsible-show'][Ashe.LANG]).store('tip:text', Ashe.text['collapsible-show-title'][Ashe.LANG]);
      // Set cookie entry
      if(id) { cookie.addItem(page + '@' + id); }
    } else {
      group.show();
      el.set('data-collapsible', 'expanded');
      el.getElement('.collapsible').set('text', Ashe.text['collapsible-hide'][Ashe.LANG]).store('tip:text', Ashe.text['collapsible-hide-title'][Ashe.LANG]);
      // Remove cookie entry
      if(id) { cookie.removeItem(page + '@' + id); }
    }
  };
  
  // Inject triggers -----------------------------------------------------------
  els.each(function(el) {
    var trigger = new Element('a', { 'class': 'collapsible', 'text': Ashe.text['collapsible-hide'][Ashe.LANG] }).store('tip:text', Ashe.text['collapsible-hide-title'][Ashe.LANG]);
    
    el.set('data-collapsible', 'expanded');
    el.grab(trigger);
  });
  
  // Tips
  var tips = new Tips($$('.collapsible'), { className: 'section-tip' });
  
  // The events ----------------------------------------------------------------
  document.body.addEvent('click:relay(.collapsible)', function(e) {
    els = $$('[data-collapsible]');
    if(e.control) {
      // Hide all
      els.each(function(el) {
        if(el.get('data-collapsible') == 'expanded') {
          toggle(el);
        }
      });
    } else if(e.alt) {
      // Show all
      els.each(function(el) {
        if(el.get('data-collapsible') == 'collapsed') {
          toggle(el);
        }
      });
    } else {
      toggle(this.getParent());
    }
  });
  
  // Restore state -------------------------------------------------------------
  var data = cookie.getData('flat') || [];
  data.each(function(item) {
    var data = item.split('@');
    if(data[0] == page) {
      var id = data[1];
      var el = $(id).getFirst();
      var group = el.getAllNext();
      group.hide();
      el.set('data-collapsible', 'collapsed');
      el.getElement('.collapsible').set('text', Ashe.text['collapsible-show'][Ashe.LANG]).store('tip:text', Ashe.text['collapsible-show-title'][Ashe.LANG]);
    }
  });
  
};



/*
** Function DLWidget ===========================================================
** Definition list widgetizer, turns DLs into "display: table"-able structures.
**
** Don't pass in elements, pass in a string base selector instead, such as 'dl.foo'! This saves us some looping.
** Adds a "widgetized" class to passed in DLs.
** If an element with a class matching the 'captionClass' option is found before the passed in element, it is used as the caption for the widget (to be made "display: table-caption" in the CSS).
** Established groups ("rows") are given the class name passed in as the option 'groupClass'.
*/

var DLWidget = function(base, options) {
  
  var defaults = {
    captionClass : 'caption',
    groupClass   : 'group'
  };
  
  options = options || {};
  options = $merge(defaults, options);
  
  // Make groups
  $$(base + ' dt').each(function(dt) {
    var group   = [];
    var wrapper = new Element('div', { 'class': options.groupClass });
    var node    = dt;
    
    group.push(dt);
    
    while(node.getNext()) {
      if(node.getNext().get('tag') == 'dd') {
        group.push(node.getNext());
        node = node.getNext();
      } else {
        break;
      }
    }
    
    wrapper.inject(dt, 'before');
    wrapper.adopt(group);
  });
  
  // Captions
  $$(base, base + ' dl').each(function(dl) {
    var caption = dl.getPrevious('.' + options.captionClass);
    if(caption) {
      caption.inject(dl, 'top');
      var wrapper = new Element('div', { 'class': 'wrapper' });
      wrapper.adopt(caption.getChildren());
      wrapper.inject(caption);
    }
  });
  
  // Zebra
  $$(base + ' div.group:odd').addClass('odd');
  
  //
  $$(base).addClass('widgetized');
  
};
