function $(pId) {
  return document.getElementById(pId);
}

function DeForm() {
}

// ---------------------------------------------------------------------
// Browser Detection 
// ---------------------------------------------------------------------
isMac = (navigator.appVersion.indexOf("Mac")!=-1) ? true : false; 
isDOM=(document.getElementById)?true:false
isOpera=isOpera5=window.opera && isDOM
isOpera6=isOpera && window.print
isOpera7=isOpera && navigator.userAgent.indexOf("Opera 7") > 0 || navigator.userAgent.indexOf("Opera/7") >= 0
isMSIE=isIE=document.all && document.all.item && !isOpera
isMSIE4 = ((document.all)&&(navigator.appVersion.indexOf("MSIE 4.")!=-1)) ? true : false; 
isMSIEmac = ((document.all)&&(isMac)) ? true : false; 
isNC=navigator.appName=="Netscape"
isNC4=isNC && !isDOM
isNC6=isNC && isDOM


// ---------------------------------------------------------------------
// Safe loading into window.onload
//
// Body onload utility (supports multiple onload functions) 
// ---------------------------------------------------------------------

var gDeFormSafeOnload = new Array(); 
var gDeFormSafeOnloadDelay = new Array();

function DeFormSafeAddOnload(pFunction) {
  DeFormSafeAddOnloadDelayed(pFunction, 0);
}

function DeFormSafeAddOnloadDelayed(pFunction, pDelay) {
  
  if (window.onload != DeFormSafeOnload) { 

    if (window.onload) {
      gDeFormSafeOnload.push(window.onload);
      gDeFormSafeOnloadDelay.push(0);
    }
    
    window.onload = DeFormSafeOnload; 
  }
  
  gDeFormSafeOnload.push(pFunction);
  gDeFormSafeOnloadDelay.push(pDelay);
  
} 

function DeFormSafeOnload() 
{ 
  var len = gDeFormSafeOnload.length;
  
  for (i = 0; i < len; i++) {

    if (typeof(gDeFormSafeOnload[i]) != 'function') {
      gDeFormSafeOnload[i] = new Function(gDeFormSafeOnload[i]);
    }
    
    if (gDeFormSafeOnloadDelay[i] > 0) {
      setTimeout(gDeFormSafeOnload[i], gDeFormSafeOnloadDelay[i]); 
    }
    else {
      gDeFormSafeOnload[i]();
    }  
    
  }
} 

// ---------------------------------------------------------------------
// Set a cookie
// 
// ---------------------------------------------------------------------
DeForm.SetCookie = function(cookieName, cookieValue, nDays) {
  var today = new Date();
  var expire = new Date();
  if (nDays==null || nDays==0) {
    nDays=1;
  }
   expire.setTime(today.getTime() + 3600000*24*nDays);
   document.cookie = cookieName+"="+escape(cookieValue) + ";expires="+expire.toGMTString();
}


// ---------------------------------------------------------------------
// Change layer content dynamically
// 
// ---------------------------------------------------------------------
DeForm.ChangeLayerContent = function(id, content) {
  lay = document.getElementById(id);
        if (!isOpera6)
        {
    previouscontent = lay.innerHTML;
                lay.innerHTML = content;
        }
  return previouscontent;
}


// ---------------------------------------------------------------------
// Add event to object
// 
// ---------------------------------------------------------------------
DeForm.AddEvent = function(pObject, pHandler, pFunction){

  if (!document.all && document.getElementById){
    pObject.setAttribute(pHandler, pFunction);
  }    
  
  //workaround for IE 5.x and IE 6
  if (document.all && document.getElementById){
    pObject[pHandler.toLowerCase()] = new Function(pFunction);
  }
}


// ---------------------------------------------------------------------
//  Loads dynamically script
// ---------------------------------------------------------------------
var gDeFormLoadedScripts = new Array();

DeForm.LoadScript = function(pScriptSrc) {
  
  // Check if script was'nt loaded already
  if (true == DeForm.in_array(pScriptSrc, gDeFormLoadedScripts)) {
    return;  
  }
  
  gDeFormLoadedScripts.push(pScriptSrc);
  
  script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = pScriptSrc;
  
  document.getElementsByTagName("head")[0].appendChild(script);
  
  return script;
}

// ---------------------------------------------------------------------
//  Loads dynamically css file
// ---------------------------------------------------------------------
var gDeFormLoadedCSS = new Array();

DeForm.LoadCSS = function(pCSSSrc, pAlwaysLoad) {
  
  // Check if script was'nt loaded already
  if (true == DeForm.in_array(pCSSSrc, gDeFormLoadedCSS) && true != pAlwaysLoad) {
    return;  
  }
  
  gDeFormLoadedCSS.push(pCSSSrc);
  
  css = document.createElement('link');
  css.rel = 'stylesheet';
  css.href = pCSSSrc;
  
  document.getElementsByTagName("head")[0].appendChild(css);
  
  return css;
}

DeForm.in_array = function(pNeedle, pHaystack) {
  for(var i in pHaystack) {
    if (pNeedle == pHaystack[i]) {
      return true;
    }  
  }  
  return false;
}

// ---------------------------------------------------------------------
// JSON Implementation taken from www.json.org
// ---------------------------------------------------------------------
/*
     json.js (modified 2006-05-02)

        USAGE:
        var jsObj = JSON.parse(jsonStr);
        var jsonStr = JSON.stringify(jsObj);
*/
var json = (function () {
     var m = {
             '\b': '\\b',
             '\t': '\\t',
             '\n': '\\n',
             '\f': '\\f',
             '\r': '\\r',
             '"' : '\\"',
             '\\': '\\\\'
         },
         s = {
             array: function (x) {
                 var a = ['['], b, f, i, l = x.length, v;
                 for (i = 0; i < l; i += 1) {
                     v = x[i];
                     f = s[typeof v];
                     if (f) {
                         v = f(v);
                         if (typeof v == 'string') {
                             if (b) {
                                 a[a.length] = ',';
                             }
                             a[a.length] = v;
                             b = true;
                         }
                     }
                 }
                 a[a.length] = ']';
                 return a.join('');
             },
             'boolean': function (x) {
                 return String(x);
             },
             'null': function (x) {
                 return "null";
             },
             number: function (x) {
                 return isFinite(x) ? String(x) : 'null';
             },
             object: function (x) {
                 if (x) {
                     if (x instanceof Array) {
                         return s.array(x);
                     }
                     var a = ['{'], b, f, i, v;
                     for (i in x) {
                         v = x[i];
                         f = s[typeof v];
                         if (f) {
                             v = f(v);
                             if (typeof v == 'string') {
                                 if (b) {
                                     a[a.length] = ',';
                                 }
                                 a.push(s.string(i), ':', v);
                                 b = true;
                             }
                         }
                     }
                     a[a.length] = '}';
                     return a.join('');
                 }
                 return 'null';
             },
             string: function (x) {
                 if (/["\\\x00-\x1f]/.test(x)) {
                     x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                         var c = m[b];
                         if (c) {
                             return c;
                         }
                         c = b.charCodeAt();
                         return '\\u00' +
                             Math.floor(c / 16).toString(16) +
                             (c % 16).toString(16);
                     });
                 }
                 return '"' + x + '"';
             }
         };

        return {
                parse: function(s) {
                        try {
                                return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                                        s.replace(/"(\\.|[^"\\])*"/g, ''))) &&
                                        eval('(' + s + ')');
                        } catch (e) {
                                return false;
                        }
                },
                stringify: s.object
        };

})();


// ---------------------------------------------------------------------
// ImgAlpha
// ---------------------------------------------------------------------
DeForm.ImgAlpha = function(pSrc, pWidth, pHeight) {

  if (isIE) {
    var img_el = document.createElement('span');
    img_el.style.display = 'block';
    img_el.style.width = pWidth + 'px';
    img_el.style.height = pHeight + 'px';
    img_el.style.border = '0';
    img_el.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + pSrc + "',sizingMethod='scale')";
    img_el.style.cursor = 'pointer';
  }
  else {
    var img_el = document.createElement('img');
    img_el.width = pWidth;
    img_el.height = pHeight;
    img_el.style.border = '0';
    img_el.src = pSrc;
    img_el.style.cursor = 'pointer';
  }
  
  return img_el;
}


// ---------------------------------------------------------------------
// Grid element
// ---------------------------------------------------------------------
DeForm.Grid = function(pInsertEl, pIconImage, pIconWidth, pIconHeight) {

  // Variables init
  this.mInsertEl = $(pInsertEl);
  this.mSelfName = pInsertEl + '_obj';
  this.mOutputEl = $(pInsertEl + '_hidden');
  this.mIconImage = pIconImage;
  this.mIconWidth = pIconWidth;
  this.mIconHeight = pIconHeight;
  
  // Setup table elements
  this.mTableEl = document.createElement('table');
  this.mTableBodyEl = document.createElement('tbody');
  this.mTableHeaderEl = document.createElement('tr');
  
  this.mTableEl.appendChild(this.mTableBodyEl);
  this.mInsertEl.appendChild(this.mTableEl);
  this.mTableBodyEl.appendChild(this.mTableHeaderEl);
  
  // Where grid data are stored
  this.mGridData = {};
  this.mGridColumns = [];
  this.mGridRows = [];
  
  // Methods
  this.AddColumn = DeForm.Grid.AddColumn;
  this.AddRow = DeForm.Grid.AddRow;
  this.DeleteRow = DeForm.Grid.DeleteRow;
  this.SerializeData = DeForm.Grid.SerializeData;
  this.UnserializeData = DeForm.Grid.UnserializeData;
  
}

DeForm.Grid.AddRow = function(pArguments) {
  
  // No data to add
  if (pArguments.length <= 0) {
    return;
  }
  
  // Create <tr> element
  tr_el = document.createElement('tr');
  
  // Save row data (reference to tr_el to allow removing it
  this.mGridRows.push(tr_el);
  
  // Record index
  index = this.mGridRows.length - 1;

  for(b in this.mGridColumns) {
    
    col_name = this.mGridColumns[b];
    
    // More data than we have columns
    if (typeof(this.mGridData[col_name]) == 'undefined') {
      continue;
    }

    this.mGridData[col_name].data[index] = pArguments[col_name];
    
    td_el = document.createElement('td');

    // Style
    td_el.style.width = this.mGridData[col_name].column_width;
    
    td_el.style.textAlign = this.mGridData[col_name].column_align;

    // Text 
    td_text = document.createTextNode(pArguments[col_name]);
    td_el.appendChild(td_text)
    
    // Append to <tr> element
    tr_el.appendChild(td_el);
  }
  
  // Last column with remove button - create only if icon was given
  if (this.mIconImage != '') {
    td_el = document.createElement('td');
    td_el.style.verticalAlign = 'middle';
    
    a_el = document.createElement('a');
    icon_el = DeForm.ImgAlpha(this.mIconImage, this.mIconWidth, this.mIconHeight);
    a_el.href = "javascript:" + this.mSelfName + ".DeleteRow(" + index + "); void(0);";
    a_el.appendChild(icon_el);
    
    td_el.appendChild(a_el);
    tr_el.appendChild(td_el);
  }
  
  this.mTableBodyEl.appendChild(tr_el);
  this.SerializeData();
}

DeForm.Grid.AddColumn = function(pName, pText, pColumnWidth, pColumnAlign, pColumnPadding) {
  
  if (typeof(this.mGridData[pName]) == 'object') {
    return;
  }

  this.mGridColumns.push(pName);
  this.mGridData[pName] = {};
  
  this.mGridData[pName].column_width = pColumnWidth;
  this.mGridData[pName].column_align = pColumnAlign;
  this.mGridData[pName].data = {};
  
  th_el = document.createElement('th');
  th_el.style.width = pColumnWidth;
  th_el.appendChild(document.createTextNode(pText));
  
  this.mTableHeaderEl.appendChild(th_el);
}

DeForm.Grid.DeleteRow = function(pIndex) {
  
  // Remove <tr> element
  this.mTableBodyEl.removeChild(this.mGridRows[pIndex]);
  this.mGridRows[pIndex] = null;

  // Remove element from grid data
  for(name in this.mGridData) {
    delete this.mGridData[name].data[pIndex];
  }
  
  this.SerializeData();
}

DeForm.Grid.SerializeData = function() {
  this.mOutputEl.value = json.stringify(this.mGridData);
}

DeForm.Grid.UnserializeData = function() {
  value = this.mOutputEl.value;
  
  if (value != '') {
    data = json.parse(value)
    
    // Detect first column
    first_col_name = '';
    
    for(name in data) {
      first_col_name = name;
      break;
    }
    
    if (first_col_name == '') {
      return;
    }
    
    for(i in data[first_col_name].data) {
      
      add_row_data = {};
    
      for(col_name in data) {
        if (typeof(data[col_name].data[i]) == 'undefined') {
          add_row_data[col_name] = '';
        }
        else {
          add_row_data[col_name] = data[col_name].data[i];
        }
      }
      this.AddRow(add_row_data);
    }
  }

  // Create blank header column (where remove button is kept) - only when icon was given
  if (this.mIconImage != '') {
    th_el = document.createElement('th');
    this.mTableHeaderEl.appendChild(th_el);
  }
}
