/* Ajax news manager based on mootools framework.
 * ----------------------------------------------------------------------------
 *
 * Copyright (C) 2009 Raphaël Bois.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * ----------------------------------------------------------------------------
 * news.js
 */

if (!MooTools || MooTools.version != '1.2.4')
  throw 'This module requires Mootools 1.2.4';

var NewsManagerStrings = new Class({
  initialize: function (extend) {
    this.msgLoading = 'Loading...';
    this.msgNewsLoading = 'News loading...';
    this.msgListError = 'Error !';
    if ($type(extend) == 'object') {
      $extend(this, extend);
    }
  }
});


var NewsManager = new Class({
  Binds: ['buildUrl', 'xmlParseNode', 'showMenu', 'showNews', 'listFail', 'listParse'],
  initialize: function (queryBaseUrl, container, strings) {
    if ($type(strings) != 'class') {
      strings = new NewsManagerStrings();
    }
    this.strings = strings;
    this.queryBaseUrl = queryBaseUrl;
    this.queryAppend = "";
    this.container = container;
    this.activeNews = null;
    this.activeMenu = null;
    this.activePath = [];
  },
  buildUrl: function (query) {
    if ($type(query) != 'string' || !query.length) {
      query = this.queryAppend;
    } else if ($chk(this.queryAppend.length)) {
    query += '&' + this.queryAppend;
    }
    if (query.length) {
      query = '?' + length;
    }
    return this.queryBaseUrl + query;
  },
  buildMenuId: function (ctx, year, month) {
    return ctx + (year ? '-' + year : '') +
      ((year && month) ? '-' + month : '');
  },
  buildNewsId: function (nid) {
    return 'thenews-' + nid;
  },
  getList: function (pel, dtype, y, m) {
    if (!pel) return;
    var request = new Request({
      url:this.buildUrl(),
      method:'post'
    });
    obj = {'mgr':this, 'el':pel, 'dtype':dtype};
    ffail = function(xhr) {
      this.mgr.listFail(this.el);
    }.bind(obj);
    fsuccess = function(rTxt, rXML) {
      this.mgr.listParse(this.el, this.dtype, rXML);
    }.bind(obj);
    request.addEvent('failure', ffail);
    request.addEvent('success', fsuccess);
    var pdata = {};
    pdata['dtype'] = dtype;
    if (y) {
      var d = '' + y;
      if (m) {
        d += '-' + m;
      }
      pdata['date'] = d;
    }
    pel.set('html', '<li class="loading">'+this.strings.msgLoading+'</li>');
    request.send({'data':pdata});
  },
  showMenu: function (elt, dtype, y, m) {
    //alert($type(elt) + " - " + elt);
    el_ul = $(elt.getElement('ul'));
    var do_load = false;
    if (el_ul) {
      el = $(el_ul.getElement('li.error'));
      if (el && el.parentNode == el_ul) {
        do_load = true; /* Try to load again ! */
      }
    } else {
      el_ul = new Element('ul');
      elt.appendChild(el_ul);
      do_load = true;
    }
    while ((it = this.activePath.pop()) != null) {
      if (it == elt.parentNode) {
        this.activePath.push(it);
        break;
      }
      this.hideElement(it);
      $(it.parentNode).removeClass('active');
    }
    if (do_load) {
      this.getList(el_ul, dtype, y, m);
    }
    this.showElement(el_ul);
    elt.addClass('active');
    this.activePath.push(el_ul);
  },
  showNews: function (elt, nid) {
    news_id = this.buildNewsId(nid);
    n_el = $(news_id);
    this.hideElement(this.activeNews);
    if (this.activeMenu)
      this.activeMenu.removeClass('active');
    this.activeNews = null;
    this.activeMenu = $(elt);
    elt.addClass('active');
    if (n_el) {
      this.showElement(n_el);
    } else {
      n_el = new Element('div', {
        'id': news_id,
        'html': '<span class="loading">'+this.strings.msgNewsLoading+'</span>',
        'style': {
          'display': 'block',
          'visibility': 'visible'
        }
      });
      this.container.appendChild(n_el);
      var pdata = { 'dtype': 'news', 'nid': nid };
      n_el.set('load', {
        url: this.buildUrl(),
        method: 'post',
        data: pdata,
        async: true,
        evalScripts: false
      });
      n_el.load();
    }
    this.activeNews = n_el;
  },
  hideElement: function (el) {
    if (el) {
      el.setStyle('display', 'none');
      el.setStyle('visibility', 'hidden');
    }
  },
  showElement: function (el) {
    if (el) {
      el.setStyle('display', 'block');
      el.setStyle('visibility', 'visible');
    }
  },
  listFail: function (el) {
    el.set('html', '<li class="error">'+this.strings.msgListError+'</li>');
  },
  listParse: function (el, dtype, rXML) {
    if (!el) return;
    if (!rXML || !rXML.documentElement ||
        rXML.documentElement.nodeName != 'news') {
      this.listFail(el);
      return;
    }
    el.empty();
    x = rXML.documentElement.childNodes;
    for (var i=0; i < x.length; i++) {
      e = this.nodeToElement(x[i], dtype);
      if (e)
        el.appendChild(e);
    }
  },
  nodeToElement: function (node, dtype) {
    switch (node.nodeName.toLowerCase()) {
      case 'menu':
        try {
          y = parseInt(node.getAttribute('year'), 10);
        } catch (e) {
          return null; /* Should always have a "year" attribute. */
        }
        try {
          m = parseInt(node.getAttribute('month'), 10);
        } catch (e) {
          m = 0; /* Month is optional. */
        }
        el_li = new Element('li', {'class': 'menu'});
        fshow = function() {
          this.t.showMenu(this.el, this.dt, this.y, this.m);
          return false;
        }.bind({t:this, el:el_li, dt:dtype, y:y, m:m});
        el_a = new Element('a', {
          'href': '#',
          'html': node.childNodes[0].nodeValue, /* XXX proper way ? */
          'events': { 'click': fshow }
        });
        el_li.appendChild(el_a);
        return el_li;
      case 'item':
        try {
          nid = node.getAttribute('nid');
          ndate = node.getAttribute('date');
        } catch (e) { return null; }
        if (!nid || !ndate) { return null; }
        ndate = '<span class="date">'+ndate+'</span>';
        el_li = new Element('li', {'class': 'item'});
        fshow = function() {
          this.t.showNews(this.el, this.nid);
          return false;
        }.bind({t:this, el:el_li, nid:nid});
        el_a = new Element('a', {
          'href': '#',
          'html': ndate+' '+node.childNodes[0].nodeValue,
          'events': { 'click': fshow }
        });
        el_li.appendChild(el_a);
        return el_li;
      default:
        return null;
    }
  }
});

