/** @file bau.general.js
 *  @brief this file contains general Bauglir object definition and extending Javascript objects
 *  @version $Id: bau.general.js,v 1.21 2009-05-11 20:48:39 bauglir Exp $
 *  @author Bronislav Klucka, Bronislav.Klucka@bauglir.com,
 *          Copyright &copy; 2009+ Bronislav Klucka
 *
 * This script is licenced under BSD licence: http://licence.bauglir.com/bsd.php
 *
 *
 */



/** GENERIC JS OBJECT PROTOTYPES **/

// ARRAY PROTOTYPES

/**
 * trigger callback function on each value (value is passed as first parametr, array is passed as second, index of value as third)
 *
 * if function returns false, traversing is stopped
 *
 * @param function callback
 */
Array.prototype.each = function(callback)
{
  if (callback.constructor != Function) return;
  for(var i = 0, j = this.length; i < j; ++i)
  {
    var res = callback(this[i], this, i);
    if (res === false) break;
  }
}

/**
 * returns index of value
 * if not founded -1 returned
 * @param mixed value
 * @return int
 */
if(!Array.indexOf)
{
  Array.prototype.indexOf = function(value)
  {
    for(var i = 0, j = this.length; i < j; i++)
    {
      if(this[i] == value) return i;
    }
	  return -1;
  }
}

/**
 * whether array contais value
 * @param value value to search for
 * @return bool
 */
Array.prototype.contains = function(value)
{
  return this.indexOf(value) > - 1;
}

// STRING PROTOTYPES

/**
 * function to remove trailing white characters from string
 */
String.prototype.trim = function()
{
  return (this.replace(/^[\s\xA0]+/, "").replace(/[\s\xA0]+$/, ""));
};

/**
 * function to remove trailing white characters from string
 * @param string text, text to trim
 */
String.trim = function(text)
{
  return (text.replace(/^[\s\xA0]+/, "").replace(/[\s\xA0]+$/, ""));
};

/**
 * function to test whether text is email
 */
String.prototype.IsEmail = function()
{
  var reg = /^((?:(?:(?:[a-zA-Z0-9][\.\-\+_]?)*)[a-zA-Z0-9])+)\@((?:(?:(?:[a-zA-Z0-9][\.\-_]?){0,62})[a-zA-Z0-9])+)\.([a-zA-Z0-9]{2,6})$/;
  return reg.test(this);
}

/**
 * function to test whether text is email
 * @param string text, text to text
 */
String.IsEmail = function(text)
{
  var reg = /^((?:(?:(?:[a-zA-Z0-9][\.\-\+_]?)*)[a-zA-Z0-9])+)\@((?:(?:(?:[a-zA-Z0-9][\.\-_]?){0,62})[a-zA-Z0-9])+)\.([a-zA-Z0-9]{2,6})$/;
  return reg.test(text);
}

/**
 * return random uppercase character
 * @return string
 */
String.RandomChar = function()
{
  return String.fromCharCode(65 + Math.round(Math.random() * 25));
}

String.PadLeft = 0;
String.PadRight = 1;
String.PadBoth = 2;

/**
 * return string with newLength length (or bigger according to padString and padding)
 * @return int newLength new length
 * @return string padString string to be appended to
 * @return int padding where to add padString to
 */
String.prototype.Pad = function(newLength, padString, padding)
{
  var result = this;
  while (result.length < newLength)
  {
    if (padding == String.PadLeft) result = padString + result;
    else if (padding == String.PadRight) result = result + padString;
    else if (padding == String.PadBoth) result = padString + result + padString;
  }
  return result;
}

// NUMBER PROTOTYPES

Number.Integer = 1;
Number.Int = Number.Integer;
Number.Float = 2;

/**
 * return string with newLength length (or bigger according to padString and padding)
 * @return int newLength new length
 * @return string padString string to be appended to
 * @return int padding where to add padString to
 */
Number.prototype.Pad = function(newLength, padString, padding)
{
  var s = this + '';
  return s.Pad(newLength, padString, padding);
}

// DATE PROTOTYPES

/**
 * format date and time according to passed string
 * see Date.prototype.Format() for description
 * @param string formatString string to format date
 * @param Date date date to format
 * @return string
 */
Date.Format = function(formatString, date)
{
  try { return date.Format(formatString); } catch(e) {return "";}
}

/**
 * format date and time according to passed string
 *
 * d: Day of the month, 2 digits with leading zeros  (01 to 31)
 * j: Day of the month without leading zeros (1 to 31)
 * m: Numeric representation of a month, with leading zeros (01 through 12)
 * n: Numeric representation of a month, without leading zeros (1 through 12)
 * Y: A full numeric representation of a year, 4 digits (1999 or 2003);
 * G: 24-hour format of an hour without leading zeros (0 through 23)
 * H: 24-hour format of an hour with leading zeros (00 through 23)
 * i: Minutes with leading zeros (00 to 59)
 * s: Seconds, with leading zeros (00 through 59)
 * 
 * to prevent char from being expanded use backslash to escape it
 *
 *
 * @param formatString string to format date
 * @return string
 */
Date.prototype.Format = function(formatString)
{
  /*
  var j = this.getDate();
  var n = this.getMonth() + 1;
  var G = this.getHours();
  var d =
  */
  var index = 0;
  var length = formatString.length;
  var result = new Array();
  while (index < length)
  {
    var chr = (formatString.substr(index, 1));
    //var chr = formatString[index];
    //alert(chr);
    switch(chr)
    {
      case "d": result.push(this.getDate().Pad(2, '0', String.PadLeft)); break;
      case "j": result.push(this.getDate()); break;
      case "m": result.push(this.MonthOfYear().Pad(2, '0', String.PadLeft)); break;
      case "n": result.push(this.MonthOfYear()); break;
      case "Y": result.push(this.getFullYear()); break;
      case "G": result.push(this.getHours()); break;
      case "H": result.push(this.getHours().Pad(2, '0', String.PadLeft)); break;
      case "i": result.push(this.getMinutes().Pad(2, '0', String.PadLeft)); break;
      case "s": result.push(this.getSeconds().Pad(2, '0', String.PadLeft)); break;
      default: result.push(chr);

    }
    index++;
  }
  //alert(this + "\n\n" + formatString + "\n\n" + result);
  return result.join("");
}


//2009-05-09 00:00:00
/**
 * return new date time according to datetime
 * @param string datetime date time in yyyy-mm-dd hh:nn:ss format
 * @return null|Date() if datetime is 0000-00-00 00:00 or 0000-00-00 00:00:00 then null is returned otherwise new Date object is created
 */
Date.DateTime = function(datetime)
{
  datetime = datetime.trim();
  if (!datetime || datetime == '0000-00-00 00:00' || datetime == '0000-00-00 00:00:00' || datetime == '0000-00-00' ) return null;
  else
  {
    try
    {
      var d = new Date();
      d.DateTime(datetime);
      return d;
    }
    catch(e) {return null;}
  }
}

/**
 * return days in month
 * @return int
 */
Date.prototype.DaysInAMonth = function()
{
  var dt = new Date(this);
  var month = dt.getMonth();
  var day = 28;
  while(month == dt.getMonth())
  {
    day++;
    dt.setDate(day);
  }
  return day - 1;
}

/**
 * set/get time in hh:nn format
 * @param string datetime
 * @return string
 */
Date.prototype.TimeShort = function(datetime)
{
  if (datetime) this.Time(datetime);
  return this.getHours().Pad(2, '0', String.PadLeft) + ":" +
         this.getMinutes().Pad(2, '0', String.PadLeft);
}

/**
 * set/get time in hh:nn or hh:nn:ss  format
 * @param string datetime
 * @return string
 */
Date.prototype.Time = function(datetime)
{
  var dt = new Date(this);
  if (!datetime)
  {
    datetime = '';
    datetime += dt.getHours().Pad(2, '0', String.PadLeft) + ":";
    datetime += dt.getMinutes().Pad(2, '0', String.PadLeft) + ":";
    datetime += dt.getSeconds().Pad(2, '0', String.PadLeft);
  }
  try
  {

    if (datetime.length == 8)
    {
      var reg = /(\d{2}):(\d{2}):(\d{2})/;
      var parts = datetime.match(reg);
      this.setHours(parts[1], parts[2], parts[3], 0);
    }
    else if (datetime.length == 5)
    {
      var reg = /(\d{2}):(\d{2})/;
      var parts = datetime.match(reg);
      this.setHours(parts[1], parts[2], 0, 0);
    }
    return datetime;
  }
  catch(e) {return ''}
}

/**
 * set/get time in yyyy-mm-dd  format
 * @param string date
 * @return string
 */
Date.prototype.Date = function(datetime)
{
  var dt = new Date(this);
  if (!datetime)
  {
    datetime = '';
    datetime += dt.getFullYear() + "-";
    datetime += dt.MonthOfYear().Pad(2, '0', String.PadLeft) + "-";
    datetime += dt.getDate().Pad(2, '0', String.PadLeft);
  }
  try
  {

    var reg = /(\d{4})-(\d{2})-(\d{2})/;
    var parts = datetime.match(reg);
    this.setFullYear(parts[1], parts[2] - 1, parts[3]);
    this.setHours(0, 0, 0, 0);
    return datetime;
  }
  catch(e) {return ''}
}

/**
 * set/get time in yyyy-mm-dd hh:nn:ss format
 * @param string datetime
 * @return string
 */
Date.prototype.DateTime = function(datetime)
{
  var dt = new Date(this);
  if (!datetime)
  {
    datetime = '';
    datetime += dt.getFullYear() + "-";
    datetime += dt.MonthOfYear().Pad(2, '0', String.PadLeft) + "-";
    datetime += dt.getDate().Pad(2, '0', String.PadLeft) + " ";
    datetime += dt.getHours().Pad(2, '0', String.PadLeft) + ":";
    datetime += dt.getMinutes().Pad(2, '0', String.PadLeft) + ":";
    datetime += dt.getSeconds().Pad(2, '0', String.PadLeft);
  }
  try
  {
    if (datetime.length == 19)
    {
      var reg = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/;
      var parts = datetime.match(reg);
      this.setFullYear(parts[1], parts[2] - 1, parts[3]);
      this.setHours(parts[4], parts[5], parts[6], 0);
    }
    else if (datetime.length == 16)
    {
      var reg = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})/;
      var parts = datetime.match(reg);
      this.setFullYear(parts[1], parts[2] - 1, parts[3]);
      this.setHours(parts[4], parts[5], 0, 0);
    }
    else if (datetime.length == 10)
    {
      var reg = /(\d{4})-(\d{2})-(\d{2})/;
      var parts = datetime.match(reg);
      this.setFullYear(parts[1], parts[2] - 1, parts[3]);
      this.setHours(0, 0, 0, 0);
    }
    return datetime;
  }
  catch(e) {return ''}
}

/**
 * return day of week (1 for monday, 7 for sunday)
 */
Date.prototype.DayOfWeek = function()
{
  var d = this.getDay();
  return (d == 0) ? 7 : d;
}


/**
 * get/set month of year (1 for January, 12 for December)
 * @param int|null newMonth
 */
Date.prototype.MonthOfYear = function(newMonth)
{
  var d = 0;
  if (newMonth + 0) this.setMonth(newMonth - 1)
  d = this.getMonth();
  return d + 1;
}






/** DECLARE PRO2-SOFT NAMESPACE **/

var Bauglir = {};

Bauglir.libVersion = '000.900';


Bauglir.CreateCookie = function (name, value, minutes)
{
  var expires = "";
	if (minutes)
  {
		var date = new Date();
		date.setTime(date.getTime()+(minutes*60*1000));
		expires = "; expires="+date.toGMTString();
	}
	document.cookie = name+"="+value+expires+"; path=/";
}

Bauglir.ReadCookie = function (name, defaultValue)
{
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i = 0, j = ca.length; i < j; i++)
  {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return defaultValue;
}

Bauglir.EraseCookie = function (name)
{
	Bauglir.CreateCookie(name,"",-1);
}

/**
* returns integer value from string,
*
* @param mixed x
* @param integer default default value if parameter is not integer
* @return integer
*/
Bauglir.Int = function (x, defaultValue)
{
  if (defaultValue == null) defaultValue = 0;
	if (x != null)
	{
		x = parseInt(x);
		if (isNaN(x)) x = defaultValue;
    defaultValue = x;
	}
	return defaultValue;
}

/**
* returns float value from string
* decimal separators can be either point or comma
*
* @param mixed x
* @param float default default value if parameter is not float
* @return float
*/
Bauglir.Float = function (x, defaultValue)
{
  x = x.replace(",", '.');
  if (defaultValue == null) defaultValue = 0;
	if (x != null)
	{
		x = parseFloat(x);
		if (isNaN(x)) x = defaultValue;
    defaultValue = x;
	}
	return defaultValue;
}

/**
 * log data to browser cosole
 * @param string text
 */
Bauglir.Log = function(text)
{
  try {opera.postError(text);} catch(e) {};
  try {console.log(text);} catch(e) {};
}

/**
 * function converts text to html encoded text (&lt;, &gt;, etc.)
 * @param string text
 * @return string
 */
Bauglir.ToHtml = function(text)
{
  var translation = new Array();
  translation['&'] = "&amp;";
  translation['<'] = "&lt;";
  translation['>'] = "&gt;";
  for(var chr in translation)
  {
    var tr = translation[chr];
    text = text.replace(chr, tr);
  }
  return text;
}













/*********************************/
/******** /CALENDAR **************/
/*********************************/

Bauglir.Calendar = {};

Bauglir.Calendar.Days = new Array();
Bauglir.Calendar.Days['en'] = new Array();
Bauglir.Calendar.Days['en'][1] = 'Mo';
Bauglir.Calendar.Days['en'][2] = 'Tu';
Bauglir.Calendar.Days['en'][3] = 'We';
Bauglir.Calendar.Days['en'][4] = 'Th';
Bauglir.Calendar.Days['en'][5] = 'Fr';
Bauglir.Calendar.Days['en'][6] = 'Sa';
Bauglir.Calendar.Days['en'][7] = 'Su';
Bauglir.Calendar.Days['cs'] = new Array();
Bauglir.Calendar.Days['cs'][1] = 'po';
Bauglir.Calendar.Days['cs'][2] = 'ut';
Bauglir.Calendar.Days['cs'][3] = 'st';
Bauglir.Calendar.Days['cs'][4] = 'čt';
Bauglir.Calendar.Days['cs'][5] = 'pá';
Bauglir.Calendar.Days['cs'][6] = 'so';
Bauglir.Calendar.Days['cs'][7] = 'ne';
Bauglir.Calendar.Months = new Array();
Bauglir.Calendar.Months['en'] = new Array();
Bauglir.Calendar.Months['en'][1] = 'January';
Bauglir.Calendar.Months['en'][2] = 'February';
Bauglir.Calendar.Months['en'][3] = 'March';
Bauglir.Calendar.Months['en'][4] = 'April';
Bauglir.Calendar.Months['en'][5] = 'May';
Bauglir.Calendar.Months['en'][6] = 'June';
Bauglir.Calendar.Months['en'][7] = 'July';
Bauglir.Calendar.Months['en'][8] = 'August';
Bauglir.Calendar.Months['en'][9] = 'September';
Bauglir.Calendar.Months['en'][10] = 'October';
Bauglir.Calendar.Months['en'][11] = 'November';
Bauglir.Calendar.Months['en'][12] = 'December';
Bauglir.Calendar.Months['cs'] = new Array();
Bauglir.Calendar.Months['cs'][1] = 'leden';
Bauglir.Calendar.Months['cs'][2] = 'únor';
Bauglir.Calendar.Months['cs'][3] = 'březen';
Bauglir.Calendar.Months['cs'][4] = 'duben';
Bauglir.Calendar.Months['cs'][5] = 'květen';
Bauglir.Calendar.Months['cs'][6] = 'červen';
Bauglir.Calendar.Months['cs'][7] = 'červenec';
Bauglir.Calendar.Months['cs'][8] = 'srpen';
Bauglir.Calendar.Months['cs'][9] = 'září';
Bauglir.Calendar.Months['cs'][10] = 'říjen';
Bauglir.Calendar.Months['cs'][11] = 'listopad';
Bauglir.Calendar.Months['cs'][12] = 'prosinec';




/*********************************/
/******** /CALENDAR **************/
/*********************************/




/*
Bauglir.Browser.Exception = {}

Bauglir.Browser.Exception.Stack = function()
{
  return {
    functionName: '',
    fileName: '',
    fileLine: 0,
    arguments: new Array()

  }
};



function showCallStack()
{

  try
  {
    raise.error = 5;
    alert('fffff');
  } catch(e) {
    var res = '';
    //for (var i in e) res += i + ": " + e[i] + "\n";
    //opera:  Backtrace
    //FF: stack
    //IE
    //alert(e.stack);
    //alert(res);

    var callstack = new Array();
    var parts = new Array();
    if (Bauglir.Browser.Application == 'Firefox')
    {
      parts = e.stack.split("\n");
      parts.shift();
      var part;
      var f = showCallStack.caller;
      for (var i = 0, j = parts.length; i < j; ++i)
      {
        part = parts[i];
        if (!part) continue;
        var pParts = part.split("@");
        var fName = pParts[0].match(/^(\w+)\(/);
        fName = fName ? fName[1] : 'unknown';
        pParts = pParts[1].split(":");
        var fiName = pParts[0] + ":" + pParts[1];
        var fiLine = pParts[2];
        var args = new Array();
        if (f != null)
        {
          for(var k = 0, l = f.arguments.length; k < l; ++k)
          {
            args.push(f.arguments[k]);
          }
          f = f.caller;
        }
        var exception = Bauglir.Browser.Exception.Stack();
        exception.fileName = fiName;
        exception.arguments = args;
        exception.fileLine = fiLine;
        exception.functionName = fName;
        callstack.push(exception);
      }
      alert(callstack.length);
    }
    else if (Bauglir.Browser.Application == 'Opera')
    {
      //for (var f in e) alert(f + ":: " + e[f]);
      var bcktrace = e.message.split("Backtrace:");
      if (bcktrace.length > 0)
      {
        bcktrace = bcktrace[1].trim();
        bcktrace = bcktrace.split("\n");
        alert(bcktrace[1]);
      }
    }

    //if ()

    /*
    var currentFunction = arguments.callee.caller;
    while (currentFunction)
    {
      var fn = currentFunction.toString();
      var fname = fn.substring(fn.indexOf("function") + 8, fn.indexOf("(")) || "anonymous";
      callstack.push(fname);
      currentFunction = currentFunction.caller;
    }
    * /
    //alert(callstack.join("\n"));


  }

  return;
  var f=showCallStack,result="Call stack:\n";
  var i = 0;
  (f = f.caller);
  while(f !== null)
  {
    var sFunctionName = f.toString().match(/^function (\w+)\(/)
    sFunctionName = (sFunctionName) ? sFunctionName[1] : 'anonymous function';
    opera.postError(sFunctionName);
    result += sFunctionName;
    //result += getArguments(f.toString(), f.arguments);
    result += "\n";
    ++i;
    if (i == 10) break;
    (f = f.caller);
  }
  alert(result);
}


function getArguments(sFunction, a)
{
  var i = sFunction.indexOf(' ');
  var ii = sFunction.indexOf('(');
  var iii = sFunction.indexOf(')');
  var aArgs = sFunction.substr(ii+1, iii-ii-1).split(',')
  var sArgs = '';
  for(var i=0; i<a.length; i++)
  {
    var q = ('string' == typeof a[i]) ? '"' : '';
    sArgs+=((i>0) ? ', ' : '')+(typeof a[i])+' '+aArgs[i]+':'+q+a[i]+q+'';
  }
  return '('+sArgs+')';
}

function testFunction(a, dd)
{
  showCallStack();
}*/
