/*
  mustache.js — Logic-less templates in JavaScript

  See http://mustache.github.com/ for more info.
*/

var Mustache = function() {
  var Renderer = function() {};

  Renderer.prototype = {
    otag: "{{",
    ctag: "}}",
    pragmas: {},
    buffer: [],
    pragmas_implemented: {
      "IMPLICIT-ITERATOR": true
    },
    context: {},

    render: function(template, context, partials, in_recursion) {
      // reset buffer & set context
      if(!in_recursion) {
        this.context = context;
        this.buffer = []; // TODO: make this non-lazy
      }

      // fail fast
      if(!this.includes("", template)) {
        if(in_recursion) {
          return template;
        } else {
          this.send(template);
          return;
        }
      }

      template = this.render_pragmas(template);
      var html = this.render_section(template, context, partials);
      if(in_recursion) {
        return this.render_tags(html, context, partials, in_recursion);
      }

      this.render_tags(html, context, partials, in_recursion);
    },

    /*
      Sends parsed lines
    */
    send: function(line) {
      if(line != "") {
        this.buffer.push(line);
      }
    },

    /*
      Looks for %PRAGMAS
    */
    render_pragmas: function(template) {
      // no pragmas
      if(!this.includes("%", template)) {
        return template;
      }

      var that = this;
      var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
            this.ctag);
      return template.replace(regex, function(match, pragma, options) {
        if(!that.pragmas_implemented[pragma]) {
          throw({message: 
            "This implementation of mustache doesn't understand the '" +
            pragma + "' pragma"});
        }
        that.pragmas[pragma] = {};
        if(options) {
          var opts = options.split("=");
          that.pragmas[pragma][opts[0]] = opts[1];
        }
        return "";
        // ignore unknown pragmas silently
      });
    },

    /*
      Tries to find a partial in the curent scope and render it
    */
    render_partial: function(name, context, partials) {
      name = this.trim(name);
      if(!partials || partials[name] === undefined) {
        throw({message: "unknown_partial '" + name + "'"});
      }
      if(typeof(context[name]) != "object") {
        return this.render(partials[name], context, partials, true);
      }
      return this.render(partials[name], context[name], partials, true);
    },

    /*
      Renders inverted (^) and normal (#) sections
    */
    render_section: function(template, context, partials) {
      if(!this.includes("#", template) && !this.includes("^", template)) {
        return template;
      }

      var that = this;
      // CSW - Added "+?" so it finds the tighest bound, not the widest
      var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
              "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
              "\\s*", "mg");

      // for each {{#foo}}{{/foo}} section do...
      return template.replace(regex, function(match, type, name, content) {
        var value = that.find(name, context);
        if(type == "^") { // inverted section
          if(!value || that.is_array(value) && value.length === 0) {
            // false or empty list, render it
            return that.render(content, context, partials, true);
          } else {
            return "";
          }
        } else if(type == "#") { // normal section
          if(that.is_array(value)) { // Enumerable, Let's loop!
            return that.map(value, function(row) {
              return that.render(content, that.create_context(row),
                partials, true);
            }).join("");
          } else if(that.is_object(value)) { // Object, Use it as subcontext!
            return that.render(content, that.create_context(value),
              partials, true);
          } else if(typeof value === "function") {
            // higher order section
            return value.call(context, content, function(text) {
              return that.render(text, context, partials, true);
            });
          } else if(value) { // boolean section
            return that.render(content, context, partials, true);
          } else {
            return "";
          }
        }
      });
    },

    /*
      Replace {{foo}} and friends with values from our view
    */
    render_tags: function(template, context, partials, in_recursion) {
      // tit for tat
      var that = this;

      var new_regex = function() {
        return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
          that.ctag + "+", "g");
      };

      var regex = new_regex();
      var tag_replace_callback = function(match, operator, name) {
        switch(operator) {
        case "!": // ignore comments
          return "";
        case "=": // set new delimiters, rebuild the replace regexp
          that.set_delimiters(name);
          regex = new_regex();
          return "";
        case ">": // render partial
          return that.render_partial(name, context, partials);
        case "{": // the triple mustache is unescaped
          return that.find(name, context);
        default: // escape the value
          return that.escape(that.find(name, context));
        }
      };
      var lines = template.split("\n");
      for(var i = 0; i < lines.length; i++) {
        lines[i] = lines[i].replace(regex, tag_replace_callback, this);
        if(!in_recursion) {
          this.send(lines[i]);
        }
      }

      if(in_recursion) {
        return lines.join("\n");
      }
    },

    set_delimiters: function(delimiters) {
      var dels = delimiters.split(" ");
      this.otag = this.escape_regex(dels[0]);
      this.ctag = this.escape_regex(dels[1]);
    },

    escape_regex: function(text) {
      // thank you Simon Willison
      if(!arguments.callee.sRE) {
        var specials = [
          '/', '.', '*', '+', '?', '|',
          '(', ')', '[', ']', '{', '}', '\\'
        ];
        arguments.callee.sRE = new RegExp(
          '(\\' + specials.join('|\\') + ')', 'g'
        );
      }
      return text.replace(arguments.callee.sRE, '\\$1');
    },

    /*
      find `name` in current `context`. That is find me a value
      from the view object
    */
    find: function(name, context) {
      name = this.trim(name);

      // Checks whether a value is thruthy or false or 0
      function is_kinda_truthy(bool) {
        return bool === false || bool === 0 || bool;
      }

      var value;
      if(is_kinda_truthy(context[name])) {
        value = context[name];
      } else if(is_kinda_truthy(this.context[name])) {
        value = this.context[name];
      }

      if(typeof value === "function") {
        return value.apply(context);
      }
      if(value !== undefined) {
        return value;
      }
      // silently ignore unkown variables
      return "";
    },

    // Utility methods

    /* includes tag */
    includes: function(needle, haystack) {
      return haystack.indexOf(this.otag + needle) != -1;
    },

    /*
      Does away with nasty characters
    */
    escape: function(s) {
      s = String(s === null ? "" : s);
      return s.replace(/&(?!\w+;)|["<>\\]/g, function(s) {
        switch(s) {
        case "&": return "&amp;";
        case "\\": return "\\\\";
        case '"': return '\"';
        case "<": return "&lt;";
        case ">": return "&gt;";
        default: return s;
        }
      });
    },

    // by @langalex, support for arrays of strings
    create_context: function(_context) {
      if(this.is_object(_context)) {
        return _context;
      } else {
        var iterator = ".";
        if(this.pragmas["IMPLICIT-ITERATOR"]) {
          iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
        }
        var ctx = {};
        ctx[iterator] = _context;
        return ctx;
      }
    },

    is_object: function(a) {
      return a && typeof a == "object";
    },

    is_array: function(a) {
      return Object.prototype.toString.call(a) === '[object Array]';
    },

    /*
      Gets rid of leading and trailing whitespace
    */
    trim: function(s) {
      return s.replace(/^\s*|\s*$/g, "");
    },

    /*
      Why, why, why? Because IE. Cry, cry cry.
    */
    map: function(array, fn) {
      if (typeof array.map == "function") {
        return array.map(fn);
      } else {
        var r = [];
        var l = array.length;
        for(var i = 0; i < l; i++) {
          r.push(fn(array[i]));
        }
        return r;
      }
    }
  };

  return({
    name: "mustache.js",
    version: "0.3.0",

    /*
      Turns a template and view into HTML
    */
    to_html: function(template, view, partials, send_fun) {
      var renderer = new Renderer();
      if(send_fun) {
        renderer.send = send_fun;
      }
      renderer.render(template, view, partials);
      if(!send_fun) {
        return renderer.buffer.join("\n");
      }
    }
  });
}();
/**
 * @author Gatis Dukurs
 */
var PuiLocalization = {
    months : [
        'Janvāris',
        'Februāris',
        'Marts',
        'Aprīlis',
        'Maijs',
        'Jūnijs',
        'Jūlijs',
        'Augusts',
        'Septembris',
        'Oktobris',
        'Novembris',
        'Decembris'
    ],
    months_abbr : [
        'Jan',
        'Feb',
        'Mar',
        'Apr',
        'Mai',
        'Jūn',
        'Jūl',
        'Aug',
        'Sep',
        'Okt',
        'Nov',
        'Dec'
    ],
    days: [
        'Pirmdiena',
        'Otrdiena',
        'Trešdiena',
        'Ceturtdiena',
        'Piektdiena',
        'Sestdiena',
        'Svētdiena'
    ],
    days_abbr : [
        'P',
        'O',
        'T',
        'C',
        'Pk',
        'S',
        'Sv'
    ],
    texts : {
        // Formas msg
        str1: "Ieraksts veiksmīgi saglabāts!",
        str2: "Ieraksts veiksmīgi aktivizēts!",
        str3: "Ieraksts netika aktivizēts!",
        str4: "Ieraksts netika saglabāts",
        str5: "Vai tiešām vēlies rediģēt?",
        str6: "Vai tiešām vēlies dzēst?",
        str7: "Labi",
        str8: "Jā",
        str9: "Nepieciešama autorizācija",
        str10: "Reģistrācija",
        str11: "Nē"
    },
    
    getText: function(textKey)
    {
        return this.texts[textKey];
    }
}

/*
CSS clases used for interactions:
	Structural:
		pui-title,
		pui-content

	Visibility:
		pui-hidden,
		pui-active (selected),
		
	
	Message types:
		pui-info,
		pui-alert,
		pui-error
		
Component structure:
	domEl (html element)
*/


/*

template_name: {
	version_number: html
}
 
*/
var PuiTemplates = {
	message: {
		1: '<div class="pui-message pui-type-1 pui-{{type}} {{#isHidden}}pui-hidden{{/isHidden}}"><span class="pui-icon pui-icon-9"></span><h1 class="pui-title">{{{title}}}</h1><p>{{{content}}}</p></div>',
		2: '<div class="pui-message pui-{{type}} {{#isHidden}}pui-hidden{{/isHidden}}"><span class="pui-icon pui-icon-7"></span><h4 class="pui-title">{{{title}}}</h4><p>{{{content}}}</p></div>'
	},
	button: {
		1: '<a href="{{url}}" id="{{id}}" class="pui-button {{#isDisabled}}pui-disabled{{/isDisabled}} {{#isActive}}pui-active{{/isActive}} {{cssClass}}">{{label}}</a>'
	},
	input: {
		'text': '<input class="pui-input" type="text" name="{{id}}" id="{{id}}" value="{{value}}"/>',
		'list': '<div class="pui-input-list"><ul class="pui-list">{{#rows}}<li data-id="{{id}}">{{{name_bold}}}<span>{{description}}</span></li>{{/rows}}</ul></div>',
		'textarea': '<textarea class="pui-input" id="{{id}}" name="{{name}}"></textarea>',
		'select': '<select class="pui-input" id="{{id}}" name="{{id}}">{{#rows}}<option value="{{value}}">{{name}}</option>{{/rows}}</select>',
		'images': '<div id="{{id}}" class="pui-input"><div class="pui-panel"><label class="pui-label">Atzīmēt: </label><a class="pui-button pui-small pui-button-first pui-select-all" href="#">Visas</a><a class="pui-button pui-small pui-button-last pui-select-none" href="#">Nevienu</a><label class="pui-label"> un </label><a class="pui-button pui-small pui-batch-delete" href="#">Dzēst</a></div></div>'
	},
	helper: {
		'clear': '<a href="#" class="pui-helper-clear {{#isHidden}}pui-hidden{{/isHidden}}"></a>',
		'clear-1': '<a href="#" class="pui-helper-clear pui-custom-1 {{#isHidden}}pui-hidden{{/isHidden}}"></a>'
	},
	calendar: {
		1: '<table class="pui-calendar pui-type-1"><thead><tr class="pui-calendar-controls"><td colspan="4"><button data-action="month-previous" class="pui-calendar-month-previous pui-button pui-custom-1 pui-small"><span class="pui-icon pui-icon-2"></span></button><span>{{month}}</span><button data-action="month-next" class="pui-calendar-month-next pui-button pui-custom-1 pui-small"><span class="pui-icon pui-icon-3"></span></button></td><td colspan="3"><button data-action="year-previous" class="pui-calendar-year-previous pui-button pui-custom-1 pui-small"><span class="pui-icon pui-icon-2"></span></button><span>{{year}}</span><button data-action="year-next" class="pui-calendar-year-next pui-button pui-custom-1 pui-small"><span class="pui-icon pui-icon-3"></span></button></td></tr><tr>{{#days_abbr}}<th>{{.}}</th>{{/days_abbr}}</tr></thead><tbody>{{#body}}<tr>{{#days}}<td>{{#isCurrentMonthDate}}<a href="#" {{attrClass}} {{timestamp}}>{{day}}</a>{{/isCurrentMonthDate}}</td>{{/days}}</tr>{{/body}}</tbody></table>',
		2: '<table class="pui-calendar pui-type-2"><thead><tr class="pui-calendar-controls"><td><a href="#" class="pui-calendar-month-previous" data-action="month-previous">&lt;</a></td><td colspan="5">{{month_abbr}} {{year}}</td><td><a href="#" data-action="month-next" class="pui-calendar-month-next">&gt;</a></td></tr><tr>{{#days_abbr}}<th>{{.}}</th>{{/days_abbr}}</tr></thead><tbody>{{#body}}<tr>{{#days}}<td>{{#isCurrentMonthDate}}<a href="#" {{attrClass}} {{timestamp}}>{{day}}</a>{{/isCurrentMonthDate}}</td>{{/days}}</tr>{{/body}}</tbody></table>'
	},
	time: {
		1: '<ul class="pui-time-input-list">{{#rows}}<li><a href="#" data-timestamp={{timestamp}} class="{{cssClass}}">{{time}} {{infoText}}</a></li>{{/rows}}</ul>'
	},
	window: {
		1: '<div class="pui-window {{#isHidden}}pui-hidden{{/isHidden}}"><div class="pui-window-content">{{{content}}}</div></div>',
		2: '<div class="pui-window {{#isHidden}}pui-hidden{{/isHidden}}"><div class="pui-window-outline"><div class="pui-window-container" style="width: 497px;"><div class="pui-window-header"><h4 class="pui-title">{{{title}}}</h4><div class="pui-buttons"><a class="pui-button pui-close pui-custom-2 pui-small" href="#"><span class="pui-icon pui-icon-1"></span></a></div></div><div class="pui-message-container"></div><div class="pui-window-content">{{content}}</div><div class="pui-window-footer pui-hidden"><div class="pui-buttons"></div></div></div></div></div>',
		3: '<div class="pui-window {{#isHidden}}pui-hidden{{/isHidden}}"><div class="pui-window-shadow"><div class="pui-window-container" {{style}}><div class="pui-window-content">{{content}}</div></div></div></div>'
	},
	autocomplete: {
		1: '<span class="pui-helper-busy {{#isHidden}}pui-hidden{{/isHidden}}"></span>',
		'pick': '<div class="pui-input pui-autocomplete-item-picked {{#isDisabled}}pui-disabled{{/isDisabled}}"><ul class="pui-item-meta"><li><a class="bold pui-item-name" href="#">{{name}}</a></li><li style="" class="pui-item-description">{{description}}</li></ul><a class="pui-item-remove" href="#">Noņemt</a></div>',
		'pick-1': '<div class="pui-input pui-autocomplete-item-picked {{#isDisabled}}pui-disabled{{/isDisabled}}"><ul class="pui-item-meta"><li>{{name}}</li></ul><a class="pui-item-remove" href="#">Noņemt</a></div>'
	},
	partial: {
		'images': '<ul class="pui-manager-images-list">{{#rows}}<li data-uuid="{{uuid}}" class="pui-row"><p class="pui-item-image"><input type="checkbox" name="" class="pui-select" /><img width="92" height="70" alt="" src="{{src}}"></p><ul class="pui-item-meta"><li><a class="bold" href="#">{{name}}</a></li><li><input type="checkbox" id="set-as-{{uuid}}" {{#isDefault}}checked="checked"{{/isDefault}} class="pui-set-as-primary"/> <label for="set-as-{{uuid}}">Notikuma titulbilde</label> </li></ul><div class="pui-item-actions"><a href="#" class="pui-button pui-small pui-remove"><span class="pui-icon pui-icon-6"></span></a></div></li>{{/rows}}</ul>',
		'files': '<ul class="pui-file-list">{{#rows}}<li id="{{id}}" {{#isAlert}}class="pui-alert"{{/isAlert}}><div style="width: 0%;" class="pui-file-progress"></div><div class="pui-file-item"><span class="pui-item-title">{{name}}</span><span class="pui-item-meta">{{size}}</span><a class="pui-button pui-small pui-remove" href="#"><span class="pui-icon pui-icon-6"></span></a><span class="pui-icon pui-icon-8 pui-hidden"></span></div></li>{{/rows}}</ul>'
	},
	upload: {
		'queue': '<div><div id="pui-swf-container" style="position:absolute; left: 155px; top: 265px;"><a id="pui-swf-trigger" class="pui-button pui-small" href="#">Pievienot</a></div><div class="pui-file-list-container"></div><div class="pui-panel pui-file-upload-statusbar"><ul><li class="bold uppercase"><span class="pui-queue-files-count">0</span> / <span class="pui-queue-files-count-limit">{{fileLimit}}</span></li><li class="bold uppercase"><span class="pui-queue-size">0 B</span> / <span class="pui-queue-size-limit">{{sizeLimit}}</span></li><li></li></ul></div></div>',
	}
};

var PuiCacheNamespace = function () {
	this._storage = {};
};
PuiCacheNamespace.prototype.get = function ( key ) {
	if(isDefined(this._storage[ key ]))
		return this._storage[ key ];
	return false;
};
PuiCacheNamespace.prototype.set = function ( key, value ) {
	this._storage[ key ] = value;
};

var PuiCache = {
	_namespaces: {},
	getNamespace: function ( namespace ) {
		if(!isDefined( this._namespaces[ namespace ]))
			this._namespaces[ namespace ] = new PuiCacheNamespace;
		return this._namespaces[ namespace ];
	},
	clearNamespace: function ( namespace ) {
		this._namespaces[ namespace ] = null;
		delete(this._namespaces[ namespace ]);
	}
};


/* 
	==========================================
	Extensions for default javascript objects
	==========================================
*/
if (!Array.indexOf) {
  Array.prototype.indexOf = function (obj, start) {
    for (var i = (start || 0); i < this.length; i++) {
      if (this[i] == obj) {
        return i;
      }
    }
    return -1;
  }
}
/*
	--- Object: Date ---
*/
Date.prototype.daysInMonth = function(){
    return 32 - new Date(this.getFullYear(), this.getMonth(), 32).getDate();
};
Date.prototype.getWeekDay = function(){
    var day = this.getDay();
    if(day == 0)
        day = 7;
    return day;
};
Date.prototype.saveOnElement = function(element)
{
    element.attr('data-timestamp', this.getTime());
};
Date.prototype.restoreFromElement = function(element)
{
    if(element.attr('data-timestamp'))
        this.setTime(new Number(element.attr('data-timestamp')));
};
Date.prototype.setDateAsElementValue = function(element){
    element.val([this.getDate().pad(2), (this.getMonth() + 1).pad(2), this.getFullYear()].join('.'));
};
Date.prototype.setTimeAsElementValue = function(element){
    element.val(this.getHours().pad(2)+':'+this.getMinutes().pad(2));
};
Date.prototype.clone = function()
{
    return new Date(this.getTime());
};
Date.prototype.addMinutes = function(minutes)
{
    this.setMinutes(this.getMinutes() + minutes);
    return this;
};
Date.prototype.toCustomString = function() {
	return this.getDate().pad(2) +'.'+ (this.getMonth() + 1).pad(2) +'.'+this.getFullYear();
}
/*

	--- Object: Number ---

*/
Number.prototype.bytesConvert = function()
{
    var bytes = this.valueOf();
    var ext = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    var unitCount = 0;
    for(;bytes > 1024; unitCount++)
    	bytes /= 1024;
    return bytes.roundDecimal(2)+' '+ext[unitCount];
}
Number.prototype.roundDecimal = function(dec)
{
    var num = this.valueOf();
    return Math.round(num*Math.pow(10,dec))/Math.pow(10,dec)
};
Number.prototype.pad = function(length)
{	
    var number = this.valueOf();
    var str = '' + number;
    
    while (str.length < length) {
        str = '0' + str;
    }
   
    return str;
};

String.prototype.ltrim = function(chars) {
	chars = chars || "\\s";
	return this.valueOf().replace(new RegExp("^[" + chars + "]+", "g"), "");
}
String.prototype.rtrim = function(chars) {
	chars = chars || "\\s";
	return this.valueOf().replace(new RegExp("[" + chars + "]+$", "g"), "");
}
String.prototype.ucfirst = function () {
	var str = this.valueOf();
	return str.charAt(0).toUpperCase() + str.slice(1);
};

/*

	--- Functions: Utilities ---

*/
function logError (srtError, strComponentName, strFunctionName) {
	//console.log(['Component error: ', strComponentName, '.', strFunctionName,' ',srtError].join(''));
};
function renderTpl (template, version, data) {
	var html = Mustache.to_html(PuiTemplates[template][version], data);
	return jQuery(html);
}
function isDefined(variable)
{
	return (typeof variable !== 'undefined');
}
function isFunction(variable)
{
	return (typeof variable === 'function');
}
function isObject(variable)
{
	return (typeof variable === 'object');
}
function isArray(variable)
{
	return (variable instanceof Array)
}
function isString(variable)
{
    return (typeof variable === 'string');
}
function alignTo(element, target, options){

	// Get needed params
	var targetPosition = target.offset();
	
	var targetWidth = target.innerWidth();
	var targetHeight = target.outerHeight();
	
	var elementWidth = element.outerWidth();
	var elementHeight = element.outerHeight();
	
	var top = targetPosition.top;
	var left = targetPosition.left + parseInt(target.css('margin-left'));
	
	// Align
	if(isDefined(options.align)){
		// bottom|top|middle
		if(options.align.indexOf('top') > -1){
			top -= elementHeight;
		}
		else if(options.align.indexOf('bottom') > -1)
			top += targetHeight;
		else if(options.align.indexOf('middle') > -1)
			top += targetHeight / 2;
			
		// left|right|center
		if(options.align.indexOf('right') > -1)
			left += targetWidth;
		else if(options.align.indexOf('center') > -1)
			left += (targetWidth - elementWidth) / 2;
	}
	
	// Align point
	if(isDefined(options.alignPoint)){
		// bottom|top|middle
		if(options.alignPoint.indexOf('top') > -1){
			if(options.align.indexOf('top') > -1)
				top += elementHeight;
			else if(options.align.indexOf('bottom') > -1 || options.align.indexOf('middle') > -1)
				top += 0;
		}
		else if(options.alignPoint.indexOf('bottom') > -1){
			if(options.align.indexOf('top') > -1)
				top += 0;
			else if(options.align.indexOf('bottom') > -1 || options.align.indexOf('middle') > -1)
				top -= elementHeight;
		}
		else if(options.alignPoint.indexOf('middle') > -1){
			if(options.align.indexOf('top') > -1)
				top += elementHeight / 2;
			else if(options.align.indexOf('bottom') > -1 || options.align.indexOf('middle') > -1)
				top -= elementHeight / 2;
		}
			
		// left|right|center
		if(options.alignPoint.indexOf('right') > -1){
			if(options.align.indexOf('right') > -1 || options.align.indexOf('left') > -1)
				left -= elementWidth;
			else if(options.align.indexOf('center') > -1)
				left -= elementWidth / 2;
		}
		if(options.alignPoint.indexOf('left') > -1){
			if(options.align.indexOf('center') > -1)
				left += elementWidth / 2;
		}
		else if(options.alignPoint.indexOf('center') > -1){
			if(options.align.indexOf('right') > -1 || options.align.indexOf('left') > -1)
				left -= elementWidth / 2;
		}
	}
	
	// Offset
	if(isDefined(options.offsetTop))
		top += options.offsetTop;
	
	if(isDefined(options.offsetLeft))
		left += options.offsetLeft;
	
	// Set element position
	element.css({
		top: top+'px',
		left: left+'px'
	});
}
function sizeTo(element, target){
	var targetWidth = target.outerWidth();
	element.css({
		"width": [targetWidth,"px"].join('')
	});
}
function extend(subClass, superClass)
{
	var F = function() {};
	F.prototype = superClass.prototype;
	subClass.prototype = new F();
	subClass.prototype.constructor = subClass;
	subClass.superclass = superClass.prototype;
	
	if(superClass.prototype.constructor == Object.prototype.constructor)
		superClass.prototype.constructor = superClass;
}
function extendHash (hash1, hash2) {
	jQuery.each( hash2, function ( strKey, miscValue ) {
		if(!isDefined(hash1[ strKey ]))
			hash1[ strKey ] = miscValue;
	} );
	return hash1;
}

/* 
	==========================================
	Pui component objects
	==========================================
*/

/*

	--- Component: PuiComponentAbstract, PuiComponentInputAbstract, PuiComponentHelperAbstract ---

*/
var PuiComponentAbstract = function (objSubclassData) {
	var that = this;
	var data = {
		renders: 0,
		renderOnce: false,
		active: false,
		disabled: false,
		visible: true,
		focus: false,
		helpers: {},
		callbacks: {},
		isDisabled: function () {
			return that.isDisabled();
		},
		isActive: function () {
			return that.isActive();
		},
		isVisible: function () {
			return that.isVisible();
		},
		isHidden: function () {
			return !that.isVisible();
		}
	};
	
	if (isDefined(this.options) && isDefined(this.options.onDestroy))
		this.onDestroy = this.options.onDestroy;
		
	
	extendHash( objSubclassData, data );
};
PuiComponentAbstract.prototype._render = function ( boolIgnoreExisting ) {
	if(this.data.renderOnce && this.data.renders == 1 )
		return false;
	
	if(isDefined(this.domEl)) {
		if(this.data.renderIn == false)
			this.data.renderIn = this.domEl.parent();
		this.domEl.unbind().remove();
	}
	
	// check if there is real element
	if(isDefined(this.data.id) && jQuery( ['#', this.data.id].join('') ).length != 0 && !isDefined( boolIgnoreExisting ))
		this.domEl = jQuery( ['#', this.data.id].join('') );
	// or we have to render it
	else {
		this.domEl = renderTpl(this.template.name, this.template.version, this.data);
	}
	
	if(isDefined(this.data.renderIn))
		this.domEl.appendTo(this.data.renderIn);
		
	if(isDefined(this.data.renderAfter))
		this.domEl.insertAfter(this.data.renderAfter);
		
	if(isDefined(this.data.events))
		this.attachEvents(this.domEl, this.data.events);
	this._postRender();
	this.data.renders +=1;
};
PuiComponentAbstract.prototype._renderPartial = function () {
	if(isDefined(this.domElPartial))
		this.domElPartial.unbind().remove();
	this.domElPartial = renderTpl('partial', this.template.partial, this.data);
	if(isDefined(this.data.renderPartialAfter))
		this.domElPartial.insertAfter(this.data.renderPartialAfter);
	if(isDefined(this.data.renderPartialIn))
		this.domElPartial.appendTo(this.data.renderPartialIn);
	this._postRenderPartial();
};
PuiComponentAbstract.prototype._getCache = function () {
	return PuiCache;
};
PuiComponentAbstract.prototype.setVisible = function (bool) {	
	this.data.visible = bool;
	if(bool)
		this.domEl.removeClass('pui-hidden');
	else this.domEl.addClass('pui-hidden');
};
PuiComponentAbstract.prototype.isVisible = function () {
	return this.data.visible;
};
PuiComponentAbstract.prototype.attachEvents = function (domEl, events) {
	if(isDefined(domEl) && isDefined(events)){
		var that = this;

		jQuery.each( events, function ( strEventType, fncHandler ) {
			domEl.bind([ strEventType, that.data.namespace ].join('.'), function (event) {
				if(domEl.attr('readonly') != true && domEl.attr('readonly') != 'true' &&  domEl.attr('disabled') != true && domEl.attr('disabled') != 'true' && domEl.hasClass('pui-disabled') == false) {
					fncHandler.call(that, event);
					
					if(isDefined(that.data.callbacks) && isDefined( that.data.callbacks[ strEventType ] )) {
						var callback = that.data.callbacks[ strEventType ];
						callback.fnc.call(callback.scope, event);
					}
				} else {
					event.preventDefault();
				}
			} );
		} );
	}
};
PuiComponentAbstract.prototype.destroy = function () {
	this._preDestroy();
	
	if(isDefined(this.onDestroy)) {
		this.onDestroy();
	}
	if(isDefined(this.domEl)) { 
		this.domEl.remove();
		this.data = {};
		this.data.deleted = true;
		delete(this.domEl);
	}
};
PuiComponentAbstract.prototype.setId = function (strId){
	this.data.id = strId;
	this.domEl.attr('id', strId);
};
PuiComponentAbstract.prototype.getId = function () {
	return this.data.id;
};
PuiComponentAbstract.prototype.setActive = function(bool)
{
	this.data.active = bool;
	if(bool)
		this.domEl.addClass('pui-active');
	else this.domEl.removeClass('pui-active');
};
PuiComponentAbstract.prototype.isActive = function()
{
	return this.data.active;
};
PuiComponentAbstract.prototype.setBusy = function( bool )
{
	this.data.busy = bool;
	if(bool)
		this.domEl.addClass('pui-busy');
	else this.domEl.removeClass('pui-busy');
};
PuiComponentAbstract.prototype.isBusy = function()
{
	return this.data.busy;
};
PuiComponentAbstract.prototype.setDisabled = function(bool)
{
	this.data.disabled = bool;
	if(!isDefined(this.domEl))
		return false;
		
	if( bool ) {
		this.domEl.addClass('pui-disabled');
	} else {
		this.domEl.removeClass('pui-disabled');
	}
	this.domEl.attr('disabled', bool);
};
PuiComponentAbstract.prototype.isDisabled = function()
{
	return this.data.disabled;
};
PuiComponentAbstract.prototype.attachHelpers = function ( objHelpersAndOptions ) {
	var that = this;
	jQuery.each( objHelpersAndOptions, function ( strHelperName, objHelperOptions ) {
		objHelperOptions.component = that;
		that.data.helpers[ strHelperName ] = new window['PuiHelper'+strHelperName.ucfirst()]( objHelperOptions );
	} );
};
PuiComponentAbstract.prototype.getHelper = function ( strHelperName ) {
	if(!isDefined( this.data.helpers[ strHelperName ] ))
		return false;
	return this.data.helpers[ strHelperName ];
};
PuiComponentAbstract.prototype.appendCallback = function( strEventType, fncEventCallback, objScope ) {
	if(isFunction( fncEventCallback ))
		this.data.callbacks[ strEventType ] = {
			fnc: fncEventCallback,
			scope: objScope
		};
};
PuiComponentAbstract.prototype.setFocus = function ( bool ) {
	this.data.focus = bool;
	if( bool ) {
		if(!this.domEl.is(':focus'))
			this.domEl.focus()
	} else {
		if(this.domEl.is(':focus'))
			this.domEl.blur();
	}
};
PuiComponentAbstract.prototype.isFocus = function () {
	return this.data.focus;
};
PuiComponentAbstract.prototype.reset = function () {
	this.data.value = null;
	this.domEl.val('');
};

/*

Errors object:

	{
		labelId: 'label-id',
		inputs: [
			'input-id-1',
			'input-id-2'
			],
		messages: [
			'Message text 1',
			'message text 2'
			]
	}

*/
PuiComponentAbstract.prototype.setErrors = function ( objErrors ) {
	// setup
	this.clearErrors();
	this.data.errors = {};
	this.data.errors.label = jQuery(['label[for="', objErrors.labelId, '"]'].join(''));
	this.data.errors.label.addClass('pui-error');
	this.data.errors.inputs = [];
	this.data.errors.messages = objErrors.messages;

	var that = this;
	jQuery.each(  objErrors.inputs, function ( key, value ) {
		if(value){
			var input = jQuery(['#', value].join(''));
			input.addClass('pui-error');
			that.data.errors.inputs.push(input);
		}
	});
	// display messages
	var that = this;

	jQuery.each(this.data.errors.messages, function(index, error){
		var element = jQuery('<span class="pui-input-description pui-error"></span>');
		element.html(error).appendTo(that.domEl.parent());
	});
};
PuiComponentAbstract.prototype.clearErrors = function () {
	if(isDefined(this.data.errors)){
		this.data.errors.label.removeClass('pui-error');
		jQuery.each( this.data.errors.inputs, function ( index, input ) {
			input.removeClass('pui-error');
		});
		this.domEl.parent().find('span.pui-error').remove();
		delete(this.data.errors);
	}
};
// callbacks
PuiComponentAbstract.prototype._postRender = function () {};
PuiComponentAbstract.prototype._preDestroy = function () {};

/* --- | PuiComponentInputAbstract | --- */
var PuiComponentInputAbstract = function ( objSubclassData ) {
	var that = this;
	var data = {
		
	};
	PuiComponentInputAbstract.superclass.constructor.call(this, data);
	extendHash( objSubclassData, data );
};
// Extends: PuiComponentAbstract
extend( PuiComponentInputAbstract, PuiComponentAbstract );
// Functions: 
PuiComponentInputAbstract.prototype.setValue = function ( strValue ) {
	this.data.value = strValue;
	this.domEl.val(strValue);
};
PuiComponentInputAbstract.prototype.getValue = function () {
	this.data.value = (this.domEl.val() == '') ? false : this.domEl.val();
	if(this.data.value){
		var hash = {};
		hash[this.data.id] = this.data.value;
		return hash;
	}
		
	return false;
};

var PuiComponentCalendarAbstract = function ( objSubclassData ) {
	var that = this;
	var data = {
		month: function () {
			return PuiLocalization.months[ that._getDate().getMonth() ];
		},
		month_abbr: function () {
			return PuiLocalization.months_abbr[ that._getDate().getMonth() ];
		},
		year: function () {
			return that._getDate().getFullYear();
		},
		days_abbr: PuiLocalization.days_abbr,
		body: function () {
			return that._getBodyData();
		},
		onSelect: function ( objDate ) {},
		_date: new Date()
	};
	PuiComponentCalendarAbstract.superclass.constructor.call(this, data);
	extendHash( objSubclassData, data );
};
// Extends: PuiComponentAbstract
extend( PuiComponentCalendarAbstract, PuiComponentAbstract );
// Functions
PuiComponentCalendarAbstract.prototype._getBodyData = function () {
    var currentDate = new Date();
    var tmpDate = new Date(this._getDate().getFullYear(), this._getDate().getMonth(), 1);
    var days = this._getDate().daysInMonth();
    var day = (tmpDate.getWeekDay()-2) * -1;
    var rows_count = Math.ceil((tmpDate.getWeekDay() + days - 1) / 7);
    delete(tmpDate);

    var rows = [];
    var loopDate = this._getDate().clone();
    for(j = 0; j < rows_count; ++j){
    	var row = {
    		days: []
    	};
        for(i=0; i < 7; ++i)
        {
        	var col = {
        		day: '',
            	attrClass:[],
            	timestamp: '',
            	isCurrentMonthDate: false
            };
            if(day > 0 && day <= days){
            	loopDate.setDate(day);
                var tmpDate = new Date(this._getDate().getFullYear(), this._getDate().getMonth(), day, this._getDate().getHours(), this._getDate().getMinutes(), this._getDate().getSeconds());
                col.timestamp = ['data-timestamp="', tmpDate.getTime(), '"'].join('');
                
                var is_current_date = false;
                if(day == currentDate.getDate() && this._getDate().getMonth() == currentDate.getMonth() && this._getDate().getFullYear() == currentDate.getFullYear()) {
                    col.attrClass.push('pui-calendar-current-date');
                    is_current_date = true;
                }
                if(day == this._getDate().getDate() && !is_current_date) {
                	col.attrClass.push('pui-active');
                }
                
                is_current_date = false;
                
                if(this.data.limitDate !== false && this.data.limitDate < loopDate)
                	col.attrClass.push('pui-disabled');
                
                col.attrClass.push('pui-calendar-date');
                col.attrClass = ['class="', col.attrClass.join(' '), '"'].join('');
                col.day = day;
                col.isCurrentMonthDate = true;
            }
            if(day <= days) ++day;
            
            row.days.push(col);
        }
        rows.push(row);
    }
    return rows;
};
PuiComponentCalendarAbstract.prototype._nextMonth = function () {
	this._getDate().setMonth( this._getDate().getMonth() +1 );
	this._render();
	if(isFunction(this.data.onChange))
		this.data.onChange(this._getDate());
};
PuiComponentCalendarAbstract.prototype._nextYear = function () {
	this._getDate().setFullYear( this._getDate().getFullYear() +1 );
	this._render();
	if(isFunction(this.data.onChange))
		this.data.onChange(this._getDate());
};
PuiComponentCalendarAbstract.prototype._previousMonth = function () {
	this._getDate().setMonth( this._getDate().getMonth() -1 );
	this._render();
	if(isFunction(this.data.onChange))
		this.data.onChange(this._getDate());
};
PuiComponentCalendarAbstract.prototype._previousYear = function () {
	this._getDate().setFullYear( this._getDate().getFullYear() -1 );
	this._render();
	if(isFunction(this.data.onChange))
		this.data.onChange(this._getDate());
};
PuiComponentCalendarAbstract.prototype._setDate = function ( objDate ) {
	this.data._date = objDate;
};
PuiComponentCalendarAbstract.prototype._select = function ( event ) {
	event.preventDefault();
	var date = new Date();
	date.restoreFromElement( $(event.target) );
	this._setDate( date );
	this._render();
	// callback
	this.data.onSelect( this._getDate().clone() );
};
PuiComponentCalendarAbstract.prototype._getDate = function () {
	return this.data._date;
};

/* --- | PuiComponentHelperAbstract | --- */
var PuiComponentHelperAbstract = function ( objSubclassData ) {
	var that = this;
	var data = {
		
	};
	PuiComponentHelperAbstract.superclass.constructor.call(this, data);
	extendHash( objSubclassData, data );
};
// Extends: PuiComponenetAbstract
extend( PuiComponentHelperAbstract, PuiComponentAbstract );
// Functions
PuiComponentHelperAbstract.prototype._attach = function () {
	this.attachEvents(this.data.component.domEl, this.data.componentEvents);
	this._postAttach();
};
// Functions as placeholders only to be overwriten
PuiComponentHelperAbstract.prototype._postAttach = function () {};

/* --- | PuiHelperFormActionsAbstract | --- */
var PuiHelperFormActionsAbstract = function ( objOptions, objData ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiHelperFormActionsAbstract', 'constructor' );

	this.data = {
		component: this.options.component,
		componentEvents: false,
		namespace: 'formactions'
	};
	extendHash( this.data, objData );
	PuiHelperFormActionsAbstract.superclass.constructor.call( this, this.data );
	
	this._attach();
};
// Extends: PuiComponentHelperAbstract
extend( PuiHelperFormActionsAbstract, PuiComponentHelperAbstract );
// Callback
PuiHelperFormActionsAbstract.prototype._postAttach = function () {
	var that = this;
	this.data.component.onActionHandler = function( strAction, event ) {
		that.onActionHandler( strAction, event );
	};
};
PuiHelperFormActionsAbstract.prototype.onActionHandler = function ( strAction, event ) {
	event.preventDefault();
	if(!isDefined(this[ strAction ])){
		logError(['No form action', strAction].join(': '), 'PuiHelperFormActionsAbstract', 'onActionHandler');
		return false;
	}
		
	this[ strAction ].call( this );
};

/* 
	
	--- Component: PuiMessage, Versions: Inline, Modal ---
	 
*/
var PuiMessage = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError('No options', 'PuiMessage', 'constructor');
	
	this.template = {
		name: 'message',
		version: (isDefined(this.options.version)) ? this.options.version : 1
	};
	this.data = {
		type: (isDefined( this.options.type )) ? this.options.type : "info",
		title: (isDefined( this.options.title )) ? this.options.title : '',
		content: (isDefined( this.options.content )) ? this.options.content : '',
		renderIn: (isDefined( this.options.renderIn )) ? this.options.rendeIn : false
	};
	PuiMessage.superclass.constructor.call(this, this.data);
	this._render();
};
// Extends: PuiComponentAbstract
extend(PuiMessage, PuiComponentAbstract);

/*

	--- Component: PuiButton ---
	
	Options:
		- label
*/
var PuiButton = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError('No options', 'PuiButton', 'constructor');
	
	this.template = {
		name: 'button',
		version: 1
	};
	this.data = {
		url: "#",
		cssClass: (isDefined(this.options.cssClass)) ? this.options.cssClass : '',
		id: (isDefined( this.options.id )) ? this.options.id : false,
		events: (isDefined( this.options.events )) ? this.options.events : false,
		label: (isDefined( this.options.label )) ? this.options.label : "Button",
		renderIn: (isDefined( this.options.renderIn )) ? this.options.renderIn : false
	};
	PuiButton.superclass.constructor.call(this, this.data);
	this._render();
};
// Extends: PuiComponentAbstract
extend( PuiButton, PuiComponentAbstract );

/*

	--- Component: PuiInputAbstract, Versions: Text, Textarea, Checkbox, Select, Coordinates, List, Images ---
	
	Options:
		- id (existing/non-existing element id)
		- renderIn (render input in this element id/element)
*/
var PuiInputText = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiInputText', 'constructor' );

	this.template = {
		name: 'input',
		version: 'text'
	};
	this.data = {
		id: (isDefined( this.options.id )) ? this.options.id : false,
		renderIn: (isDefined( this.options.renderIn )) ? this.options.renderIn : false,
		events: (isDefined(this.options.events)) ? this.options.events : false
	};
	PuiInputText.superclass.constructor.call( this, this.data );
	this._render();
}
// Extends: PuiComponentInputAbstract
extend( PuiInputText, PuiComponentInputAbstract );

/* --- | PuiInputRadios | --- */
var PuiInputRadios = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiInputRadios', 'constructor' );

	this.template = {
		name: 'input',
		version: 'text'
	};
	this.data = {
		id: (isDefined( this.options.id )) ? this.options.id : false,
		name: (isDefined( this.options.name )) ? this.options.name: false,
		renderIn: (isDefined( this.options.renderIn )) ? this.options.renderIn : false,
		events: (isDefined(this.options.events)) ? this.options.events : false
	};
	PuiInputRadios.superclass.constructor.call( this, this.data );
	//this._render();
}
// Extends: PuiComponentInputAbstract
extend( PuiInputRadios, PuiComponentInputAbstract );
// Functions
PuiInputRadios.prototype.getValue = function () {
	var hash = {};
	hash[ this.data.name ] = jQuery(["input[name=", this.data.name,"]:checked"].join('')).val();
	return hash;
};
PuiInputRadios.prototype.setValue = function ( data ) {
	jQuery.each(jQuery(["input[name=", this.data.name,"]"].join('')), function ( i, v ) {
		if(jQuery(v).val() == data)
			jQuery(v).attr('checked', 'checked');
	});
};
PuiInputRadios.prototype.setDisabled = function ( bool ) {
	this.data.disabled = bool;
	
	if( bool ) {
		jQuery.each(jQuery(["input[name=", this.data.name,"]"].join('')), function ( i, v ) {
			jQuery(v).attr('disabled', true);
		});
	} else {
		jQuery.each(jQuery(["input[name=", this.data.name,"]"].join('')), function ( i, v ) {
			jQuery(v).attr('disabled', false);
		});
	}
};
PuiInputRadios.prototype.reset = function () {};




/* --- | PuiInputImages --- */
var PuiInputImages = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ) || !isDefined(this.options.url))
		logError( 'No options', 'PuiInputImages', 'constructor' );
	
	this.template = {
		name: 'input',
		version: 'images',
		partial: 'images'
	};
	this.data = {
		id: (isDefined( this.options.id )) ? this.options.id : false,
		url: this.options.url,
		renderIn: (isDefined( this.options.renderIn )) ? this.options.renderIn : false,
		_rows: [],
		rows: function () {
			return that._getRows();
		},
		uuids: []
	};
	PuiInputImages.superclass.constructor.call( this, this.data );
	
	this._render();
}
// Extends: PuiComponentInputAbstract
extend( PuiInputImages, PuiComponentInputAbstract );
// Callbacks
PuiInputImages.prototype._postRender = function () {
	var that = this;
	// attach select all event
	jQuery.each( this.domEl.find('.pui-select-all') , function ( index, domEl ) {
		that.attachEvents( jQuery(domEl), {
			'click': that.onSelectAllHandler
		} );
	} );
	// attach select none event
	jQuery.each( this.domEl.find('.pui-select-none') , function ( index, domEl ) {
		that.attachEvents( jQuery(domEl), {
			'click': that.onSelectNoneHandler
		} );
	} );
	// attach batch delete event
	jQuery.each( this.domEl.find('.pui-batch-delete') , function ( index, domEl ) {
		that.attachEvents( jQuery(domEl), {
			'click': that.onBatchDeleteHandler
		} );
	} );
	
	// find element where top render partial
	this.data.renderPartialAfter = this.domEl.find('.pui-panel');
	// hide tools
	this.data.renderPartialAfter.addClass('pui-hidden');
};
PuiInputImages.prototype._postRenderPartial = function () {
	var that = this;
	// attach remove events
	jQuery.each( this.domEl.find('.pui-remove') , function ( index, domEl ) {
		that.attachEvents( jQuery(domEl), {
			'click': that.onRemoveHandler
		} );
	} );
	// attach select events
	jQuery.each( this.domEl.find('.pui-select') , function ( index, domEl ) {
		that.attachEvents( jQuery(domEl), {
			'click': that.onSelectHandler
		} );
	} );
	
	// attach select default image
	jQuery.each( this.domEl.find('.pui-set-as-primary') , function ( index, domEl ) {
		that.attachEvents( jQuery(domEl), {
			'click': that.onSetAsPrimaryHandler
		} );
	} );
	
	// show tools
	this.data.renderPartialAfter.removeClass('pui-hidden');
};
// Functions
PuiInputImages.prototype._getRows = function () {
	return this.data._rows;
};
PuiInputImages.prototype.setRows = function ( rows ) {
	this.data._rows = rows;
	this._renderPartial();
};
// Handlers
PuiInputImages.prototype.onRemoveHandler = function ( event ) {
	event.preventDefault();
	this._selectRow(jQuery(event.currentTarget).closest('li'));
	this._delete();
};
PuiInputImages.prototype.onSelectHandler = function ( event ) {
	// visual effects
	if(jQuery(event.currentTarget).is(':checked')) {
		this._selectRow(jQuery(event.currentTarget).closest('li'));
	}
	else {
		this._deselectRow(jQuery(event.currentTarget).closest('li'));
	};
};
PuiInputImages.prototype.onSelectAllHandler = function ( event ) {
	event.preventDefault();
	var that = this;
	jQuery.each(this.domEl.find('li.pui-row'), function ( i, li) {
		that._selectRow(jQuery(li));
	} );
};
PuiInputImages.prototype.onSelectNoneHandler = function ( event ) {
	event.preventDefault();
	var that = this;
	jQuery.each(this.domEl.find('li.pui-row'), function ( i, li) {
		that._deselectRow(jQuery(li));
	} );
};
PuiInputImages.prototype.onBatchDeleteHandler = function ( event ) {
	event.preventDefault();
	var that = this;
	if(this.data.uuids.length > 0) {
		that._delete();
	}
};
PuiInputImages.prototype.onSetAsPrimaryHandler = function ( event ) {
	jQuery.each( this.domEl.find('.pui-set-as-primary') , function ( index, domEl ) {
		jQuery(domEl).attr('checked', false);
	} );
	jQuery(event.currentTarget).attr('checked', true);
	jQuery.post('/calendar/file-manager/setdefault', {
		evuuid: this.data.form.data.uuid,
		imuuid: event.currentTarget.id.split('-').pop() 
	}, function (json) {
		
	});
};
// functions
PuiInputImages.prototype._selectRow = function ( domEl ) {
	domEl.addClass('pui-active');
	domEl.find('input.pui-select').attr('checked', 'checked');
	this.data.uuids.push(domEl.attr('data-uuid'));
};
PuiInputImages.prototype._deselectRow = function ( domEl ) {
	domEl.removeClass('pui-active');
	domEl.find('input.pui-select').attr('checked', false);
	var uuid = domEl.attr('data-uuid');
	
	this.data.uuids = jQuery.grep(this.data.uuids, function ( n ) {
  		return  n != uuid;
	});
};
PuiInputImages.prototype._removeRow = function ( uuid ) {
	this.domEl.find('li[data-uuid='+uuid+']').remove();
	this.data.uuids = jQuery.grep(this.data.uuids, function ( n ) {
  		return  n != uuid;
	});
	this.data._rows = jQuery.grep(this.data._rows, function ( n ) {
  		return  n.uuid != uuid;
	});
	
	if(this.data._rows.length == 0)
		this.data.renderPartialAfter.addClass('pui-hidden');
};
PuiInputImages.prototype._delete = function () {
	var that = this;
	jQuery.post( this.data.url, {uuids: this.data.uuids},  function (json) {
		if(json.status == 1) {
			if(json.rows !== null){
				jQuery.each(json.rows, function ( index, uuid ) {
					that._removeRow(uuid);
				});
			}
		}
	});
};
PuiInputImages.prototype.getValue = function () {
	var hash = {};
	hash['images'] = this.data._rows.length; 
	return hash;
};
PuiInputImages.prototype.setValue = function ( rows ) {
	if(rows)
		this.setRows( rows );
};
PuiInputImages.prototype.setDisabled = function ( bool ) {
	this.data.disabled = true;
	
	if( bool ) {
		this.domEl.addClass('pui-disabled');
		
		this.domEl.find('.pui-button').addClass('pui-disabled');
		this.domEl.find('.pui-button').attr('disabled', true);
		
		this.domEl.find('input').addClass('pui-disabled');
		this.domEl.find('input').attr('disabled', true);
	} else {
		this.domEl.removeClass('pui-disabled');
		
		this.domEl.find('.pui-button').removeClass('pui-disabled');
		this.domEl.find('.pui-button').attr('disabled', false);
		
		this.domEl.find('input').removeClass('pui-disabled');
		this.domEl.find('input').attr('disabled', false);
	}
};
PuiInputImages.prototype.reset = function () {
	this.domEl.find('.pui-panel').hide();
	this.setRows([]);
};

/* --- | PuiInputList | --- */
var PuiInputList = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiInputText', 'constructor' );
	
	this.template = {
		name: 'input',
		version: 'list'
	};
	this.data = {
		id: (isDefined( this.options.id )) ? this.options.id : false,
		renderIn: (isDefined( this.options.renderIn )) ? this.options.renderIn : false,
		rows: function () {
			return that._getRows();
		},
		_rows: false,
		namespace: 'inputlist'
	};
	
	if(isDefined( this.options.onSelect ))
		this.data.onSelect = this.options.onSelect;
	
	PuiInputList.superclass.constructor.call( this, this.data );
};
// Extends 
extend( PuiInputList, PuiComponentInputAbstract );
// Callbacks
PuiInputList.prototype._postRender = function () {
	var that = this;
	jQuery.each( this.domEl.find('li'), function (index, objEl) {
		that.attachEvents( jQuery(objEl), {
			'mousedown': that._select,
			'mouseenter': that.onMouseenterHandler
		});
	} );
	
	// bind key events
	this.attachEvents( jQuery( document ), {
		'keydown': that.onKeyDownHandler
	});
	// select first child
	this._setCurrent(this.domEl.find('li:first-child'));
};
PuiInputList.prototype._preDestroy = function () {
	// unbind key events
	jQuery( document ).unbind(['keydown', this.data.namespace].join('.'));
};
PuiInputList.prototype._getRows = function () {
	return this.data._rows;
};
PuiInputList.prototype.setRows = function ( hashRows ) {
	this.data._rows = hashRows;
	this._render();
};
PuiInputList.prototype._select = function ( event ) {
	jQuery( document ).unbind(['keydown', this.data.namespace].join('.'));
	
	event.preventDefault();
	var id = this.data.current.attr('data-id');
	var that = this;
	jQuery.each( this._getRows(), function ( index, row ) {
		
		if(row.id == id && isDefined(that.data.onSelect) )
			that.data.onSelect( row );
	} );
};
// functions
PuiInputList.prototype._setCurrent = function ( element ) {
	if(isDefined(element.length) && element.length == 0)
		return false;
	
	this.domEl.find('.pui-focus').removeClass('pui-focus');
	jQuery( element ).addClass('pui-focus');
	this.data.current = jQuery( element );
};
// Handlers
PuiInputList.prototype.onKeyDownHandler = function ( event ) {
	if(jQuery.inArray( event.keyCode, [38, 40, 13]) == -1)
		return false;
		
	event.preventDefault();
	if(event.keyCode == 38)
		this._setCurrent(this.data.current.prev());
	if(event.keyCode == 40)
		this._setCurrent(this.data.current.next());
	if(event.keyCode == 13)
		this._select( event );
};
PuiInputList.prototype.onMouseenterHandler = function ( event ) {
	this._setCurrent(event.currentTarget);
};

/*

	--- Component: PuiCalendar ---
	
	Options:
		- renderIn (render input in this element id/element)
*/
var PuiCalendar = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiCalendar', 'constructor' );
	
	this.template = {
		name: 'calendar',
		version: (isDefined( this.options.version )) ? this.options.version : 1
	};
	this.data = {
		_date: (isDefined( this.options.date )) ? this.options.date : new Date(),
		renderIn: (isDefined( this.options.renderIn )) ? this.options.renderIn : false,
		limitDate: (isDefined(this.options.limitDate)) ? this.options.limitDate : false,
		onChange: (isDefined(this.options.onChange)) ? this.options.onChange : false 
	};
	
	if(isDefined( this.options.onSelect ))
		this.data.onSelect = this.options.onSelect;
	
	PuiCalendar.superclass.constructor.call( this, this.data );
	
	this._render();
	//console.log(this.data._date);
}
// Extends: PuiComponentInputAbstract
extend( PuiCalendar, PuiComponentCalendarAbstract );
// Function for callback
PuiCalendar.prototype._postRender = function () {
	var that = this;
	jQuery.each( this.domEl.find('.pui-calendar-date'), function (index, objEl) {
		that.attachEvents( jQuery(objEl), {
			'mousedown': that._select
		});
	} );
	
	this.attachEvents( this.domEl.find('.pui-calendar-month-previous'), {
		'mousedown': that.controlsClickHandler
	} );
	this.attachEvents( this.domEl.find('.pui-calendar-month-next'), {
		'mousedown': that.controlsClickHandler
	} );
	if(this.template.version == 1) {
		this.attachEvents( this.domEl.find('.pui-calendar-year-previous'), {
			'mousedown': that.controlsClickHandler
		} );
		this.attachEvents( this.domEl.find('.pui-calendar-year-next'), {
			'mousedown': that.controlsClickHandler
		} );
	}
};
// handlers
PuiCalendar.prototype.controlsClickHandler = function (event) {
	event.preventDefault();
	var action = jQuery(event.currentTarget).attr('data-action');

	switch (action) {
		case 'month-next': 		this._nextMonth(); 		break;
		case 'year-next': 		this._nextYear(); 		break;
		case 'month-previous': 	this._previousMonth(); 	break;
		case 'year-previous': 	this._previousYear();	break;
	}
};

/*

	--- Component: PuiWindow ---
	
	Options:
		
*/
var PuiWindow = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiWindow', 'constructor' );
	
	this.template = {
		name: 'window',
		version: (isDefined( this.options.version )) ? this.options.version : 1
	};
	this.data = {
		title: (isDefined( this.options.title )) ? this.options.title : '&nbsp',
		content: (isDefined( this.options.content )) ? this.options.content : 'no content',
		renderIn: jQuery('body'),
		_height: (isDefined(this.options.height)) ? this.options.height : false,
		style: function () {
			if(this._height)
				return ['style="max-height:', this._height, 'px;"'].join('');
			return '';
		},
		draggable: (this.template.version == 2) ? true : false, 
		visible: false,
		buttons: (isDefined( this.options.buttons )) ? this.options.buttons : false
	};
	
	PuiWindow.superclass.constructor.call( this, this.data );
	
	this._render();
}
// Extends: PuiComponentInputAbstract
extend( PuiWindow, PuiComponentAbstract );
// callback for function render
PuiWindow.prototype._postRender = function () {
	var that = this;
	
	// get elements needed for update
	this.domEl.title = this.domEl.find('.pui-window-header > .pui-title');
	this.domEl.content = this.domEl.find('.pui-window-content');
	this.domEl.footer = this.domEl.find('.pui-window-footer');
	this.domEl.buttons = this.domEl.find('.pui-window-footer > .pui-buttons');
	
	// attach close event
	this.attachEvents( this.domEl.find('.pui-close'), {
		'mousedown': function (event) {
			event.preventDefault();
			that.destroy();
		} 
	} );
	
	if(this.template.version == 3)
		this.attachEvents( this.domEl, {
			'mousedown': function (event) {
				event.preventDefault();
			} 
		} );
	
	// add buttons
	if( this.data.buttons ) {
		jQuery.each( this.data.buttons, function ( index, button ) {
			button.domEl.appendTo(that.domEl.buttons);
		} );
		this.domEl.footer.removeClass('pui-hidden');
	}
	
	// make it draggable
	if( this.data.draggable ) {
		this.domEl.draggable({
			scroll: true,
			handle: '.pui-window-header'
		});
	}
};
PuiWindow.prototype.setZindex = function ( intNumber ) {
	if(isDefined( this.domEl ))
		this.domEl.css( {
			zIndex: intNumber
		} );
};
PuiWindow.prototype.setMessage = function ( objMessage ) {
	this.domEl.find('.pui-message-container').html(objMessage.domEl);
};
PuiWindow.prototype.setContent = function ( miscContent, append ) {
	if(isString(miscContent))
		return this.domEl.content.html( miscContent );
	if(isObject( miscContent )) {
		if(isDefined( miscContent.domEl )) {
			miscContent.data.renderIn = this.domEl.content;
			
			if(isDefined( append ) && append == true)
				return miscContent.domEl.appendTo(this.domEl.content);
			
			return this.domEl.content.html( miscContent.domEl );
		}
		if(isDefined( miscContent.url )) {
			this.domEl.content.html('');
			this.setBusy( true );
			
			var that = this;
			var data = {};
			
			if(isDefined( miscContent.params )) {
				data = miscContent.params;
			}
			
			jQuery.get( miscContent.url , data, function ( strData ) {
				that.setBusy( false );
				that.domEl.content.html( strData );
				if(isFunction(miscContent.callback))
					miscContent.callback();
				that.centerInViewport();
			} );
		}
	}
};
PuiWindow.prototype.setTitle = function ( strTitle ) {
	this.domEl.title.html( strTitle );
};
// Overwrite extended function
PuiWindow.prototype.setVisible = function (bool) {	
	this.data.visible = bool;
	if(bool) {
		this.domEl.removeClass('pui-hidden');
		// if its big modal always position it in center of viewport
		if( this.template.version == 2 )
			this.centerInViewport();
	}
	else this.domEl.addClass('pui-hidden');
};
// positioning
PuiWindow.prototype.centerInViewport = function () {
	var viewportWidth = jQuery(window).width(),
        viewportHeight = jQuery(window).height(),
        scrollTop = jQuery(window).scrollTop(),
        elWidth = this.domEl.width(),
        elHeight = this.domEl.height(),
        elOffset = this.domEl.offset();
        
    this.domEl.css({
        top:[scrollTop + (viewportHeight/2) - (elHeight/2), 'px'].join(''),
        left:[(viewportWidth/2) - (elWidth/2), 'px'].join('')
    });
};

/*

	--- Component: PuiTime ---
	
	Options:
		
*/
var PuiTime = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiTime', 'constructor' );
	
	this.template = {
		name: 'time',
		version: (isDefined( this.options.version )) ? this.options.version : 1
	};
	this.data = {
		_date: (isDefined( this.options.date )) ? this.options.date : new Date(),
		renderIn: $('#div'),
		rows: function () {
			return that._getRows();
		},
		hours: 24,
		step: 0.5,
		renderOnce: true,
		showInfo: false,
		showHours: (isDefined(this.options.showHours)) ? this.options.showHours : false
	};
	
	if(isDefined( this.options.onSelect ))
		this.data.onSelect = this.options.onSelect;
	
	PuiTime.superclass.constructor.call( this, this.data );
	
	this._render();
}
// Extends: PuiComponentInputAbstract
extend( PuiTime, PuiComponentCalendarAbstract );
// callback for function render
PuiTime.prototype._postRender = function () { 
	var that = this;
	jQuery.each( this.domEl.find('.pui-date-time'), function (index, objEl) {
		that.attachEvents( jQuery(objEl), {
			'click': that._select
		});
	} );
};
// functions
PuiTime.prototype._getRows = function () {
	var that = this;
    var date = this._getDate().clone();
    if(this.data.roundTo)
    	date.setMinutes(date.getMinutes() - (date.getMinutes() % 5));
    date.setSeconds(0);
    var rows = [];
    
    var i = 0;
    while(i < this.data.hours){
    	var row = {
    		timestamp: date.getTime(),
    		time: [ date.getHours().pad(2), date.getMinutes().pad(2) ].join(':'),
    		cssClass: 'pui-date-time'
    	};
    	
    	if(this.data.showHours) {
    		row.time = [row.time, ' (', i,' st.)'].join('');
    	}
    	
    	if( isDefined(this.data.showInfo) && this.data.showInfo )
			row.infoText = ['( ' , i, ' hrs )'].join('');
    	
    	rows.push(row);
        date.addMinutes(30);
        i += this.data.step;
    }
 	return rows;
};

/*

	--- Component: PuiAutocompletePick ---
	
	Options:
		
*/
var PuiAutocompletePick = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiAutocompletePick', 'constructor' );
	
	this.template = {
		name: 'autocomplete',
		version: 'pick'
	};
	
	if(isDefined(this.options.version))
		this.template.version = this.options.version;
	
	this.data = {
		name: (isDefined( this.options.name )) ? this.options.name : 'name',
		description: (isDefined( this.options.description )) ? this.options.description : 'description',
		renderIn: (isDefined( this.options.renderIn )) ? this.options.renderIn : false,
		onRemove: (isFunction( this.options.onRemove )) ? this.options.onRemove : function () { return false; },
		namespace: 'autocompletepick',
		disabled: false,
		isDisabled: function () {
			return this.disabled;
		}
	};
	PuiAutocompletePick.superclass.constructor.call( this, this.data );
	this._render();
}
// Extends: PuiComponentInputAbstract
extend( PuiAutocompletePick, PuiComponentInputAbstract );
// Callbacks
PuiAutocompletePick.prototype._postRender = function () {
	var that = this;
	this.attachEvents( this.domEl.find('.pui-item-remove') , {
		'click': function ( event ) {
			event.preventDefault();
			that.data.onRemove();
		}
	});
};
PuiAutocompletePick.prototype._preDestroy = function () {
	if(isDefined(this.domEl))
		this.domEl.find('.pui-item-remove').unbind([ 'click', this.data.namespace ].join('.'));
};

/*

	--- Component: PuiInputTextarea ---
	
	Options:
		
*/
var PuiInputTextarea = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiInputTextarea', 'constructor' );
	
	this.template = {
		name: 'input',
		version: 'textarea'
	};
	this.data = {
		id: (isDefined( this.options.id )) ? this.options.id : false,
		renderIn: (isDefined( this.options.renderIn )) ? this.options.renderIn : false,
		events: (isDefined(this.options.events)) ? this.options.events : false
	};
	PuiInputTextarea.superclass.constructor.call( this, this.data );
	this._render();
}
// Extends: PuiComponentInputAbstract
extend( PuiInputTextarea, PuiComponentInputAbstract );

/*

	--- Component: PuiInputSelect ---
	
	Options:
		
*/
var PuiInputSelect = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiInputSelect', 'constructor' );
	
	this.template = {
		name: 'input',
		version: 'select'
	};
	this.data = {
		id: (isDefined( this.options.id )) ? this.options.id : false,
		renderIn: (isDefined( this.options.renderIn )) ? this.options.renderIn : false,
		rows: function () {
			return that._getRows();
		},
		_rows: false
	};
	PuiInputSelect.superclass.constructor.call( this, this.data );
	
	this._render();
}
// Extends: PuiComponentInputAbstract
extend( PuiInputSelect, PuiComponentInputAbstract );
// Functions
PuiInputSelect.prototype._getRows = function () {
	return this._rows;
};
PuiInputSelect.prototype.setRows = function ( rows ) {
	this._rows = rows;
	this._render(true);
};

/*

	--- Component: PuiForm ---
	
	Options:
		- id
		
*/
var PuiForm = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiForm', 'constructor' );
	
	this.template = {
		name: false,
		version: false
	};
	this.data = {
		id: (isDefined( this.options.id )) ? this.options.id : false,
		inputs: {},
		actionButtons: {},
		namespace: 'form'
	};
	PuiForm.superclass.constructor.call( this, this.data );
	
	this._render();
}
// Extends: PuiComponentInputAbstract
extend( PuiForm, PuiComponentAbstract );
// Callback
PuiForm.prototype._preDestroy = function () {
	
};
PuiForm.prototype._postRender = function () {
	this.data.status = this.domEl.attr('data-status');
	this.data.uuid = this.domEl.attr('data-uuid');
	this.data.sessionId = this.domEl.attr('data-session-id');
};
// Functions
PuiForm.prototype.addInput = function ( objInput, strNamespace ) {
	this.data.inputs[ strNamespace ] = objInput;
	this.data.inputs[ strNamespace ].data.form = this;
};
PuiForm.prototype.getInput = function ( strNamespace ) {
	return this.data.inputs[ strNamespace ];
};
PuiForm.prototype.addActionButton = function ( objButton, strAction ) {
	this.data.actionButtons[ strAction ] = objButton;
	var that = this;
	this.attachEvents( objButton.domEl, {
		'click': function (event) {
			that.onActionHandler( strAction , event);
		}
	} );
};
PuiForm.prototype.getActionButton = function ( strAction ) {
	return this.data.actionButtons[ strAction ];
};
PuiForm.prototype.serialize = function () {
	var hash = {};
	jQuery.each(this.data.inputs, function ( index, objInput ) {
		var value = objInput.getValue();
		if(value) {
			jQuery.each(value, function( key, value ) {
				hash[ key ] = value;
			});
		}
	});
	return hash;
};
PuiForm.prototype.setErrors = function (objMultipleErrors) {
	var that = this;
	jQuery.each(objMultipleErrors, function ( index, objErrors ) {
		that.getInput(index).setErrors(objErrors);
	});
};
PuiForm.prototype.clearErrors = function () {
	jQuery.each(this.data.inputs, function ( index, input ) {
		input.clearErrors();
	});
};
PuiForm.prototype.populate = function ( data ) {
	var that = this;
	jQuery.each( data, function ( i, v ) {
		that.data.inputs[ i ].setValue(v);
	} );
};
PuiForm.prototype.setDisabled = function ( bool ) {
	this.data.disabled = bool;
	if( bool ) {
		jQuery.each(this.data.inputs, function ( i, v ) {
			v.setDisabled( true );
		});
	} else {
		jQuery.each(this.data.inputs, function ( i, v ) {
			v.setDisabled( false );
		});
	}
};
PuiForm.prototype.disableButtons = function ( bool ) {
	if( bool ) {
		jQuery.each(this.data.actionButtons, function ( i, v ) {
			v.setDisabled( true );
		});
	} else {
		jQuery.each(this.data.actionButtons, function ( i, v ) {
			v.setDisabled( false );
		});
	}	
}
PuiForm.prototype.connectWith = function ( objOtherForm ) {
	this.data.connectedTo = objOtherForm;
	objOtherForm.data.connectedTo = this;
};
PuiForm.prototype.reset = function () {
	jQuery.each(this.data.inputs, function ( index, objInput ) {
		//console.log(index);
		objInput.reset();
	});
};
// Handler
PuiForm.prototype.onActionHandler = function ( strAction, event ) {}; 

/*

	--- Component: PuiInputDateTime ---
	
	Options:
		- dateFrom
		- timeFrom
		- dateTo
		- timeTo
		
*/
var PuiInputDateTime = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions )
	|| !isDefined(this.options.dateFrom) || !isDefined(this.options.timeFrom)
	|| !isDefined(this.options.dateTo) || !isDefined(this.options.timeTo))
		logError( 'No options', 'PuiInputDateTime', 'constructor' );

	this.data = {
		namespace: 'datetime'
	};
	PuiInputDateTime.superclass.constructor.call( this, this.data );
	// custom setup for this class only
	this._setup();
}
// Extends: PuiComponentInputAbstract
extend( PuiInputDateTime, PuiComponentAbstract );
// Setup
PuiInputDateTime.prototype._setup = function () {
	var that = this;
	var puiTimeDelay = 150; // // due to IE. vajag lai vispirms izpildas PuiHelperTimeInput.data.time.onSelect()
	// setup date from
	this.data.dateFrom = new PuiInputText({
		id: this.options.dateFrom,
		events: {
			'blur': function ( event ) {
				that.onChangeHandler( event, 'dateFrom' );
			}
		}
	});
	this.data.dateFrom.attachHelpers({
		'DateInput': {
			dateNamespace: 'from'
		}
	});
	
	this.domEl = this.data.dateFrom.domEl;
	
	// setup date to
	this.data.dateTo = new PuiInputText({
		id: this.options.dateTo,
		events: {
			'blur': function ( event ) {
				that.onChangeHandler( event, 'dateTo' );
			}
		}
	});
	this.data.dateTo.attachHelpers({
		'DateInput': {
			dateNamespace: 'to'
		}
	});
	var limitDate = this.data.dateFrom.getValue().clone();
	limitDate.setHours(limitDate.getHours() + 47);
	this.data.dateTo.getHelper('DateInput').data.limitDate = limitDate;
	
	// setup time from
	this.data.timeFrom = new PuiInputText({
		id: this.options.timeFrom,
		events: {
			'blur': function ( event ) {
				window.setTimeout(function(){that.onChangeHandler( event, 'timeFrom' );},puiTimeDelay);				
			}
		}
	});
	this.data.timeFrom.attachHelpers({
		'TimeInput': {
			dateNamespace: 'from'
		}
	});
	this.data.timeFrom.getHelper('TimeInput').data.namespace = 'dateinput';
	
	// setup time to
	this.data.timeTo = new PuiInputText({
		id: this.options.timeTo,
		events: {
			'blur': function ( event ) {
				window.setTimeout(function(){that.onChangeHandler( event, 'timeTo' );},puiTimeDelay);
			}
		}
	});
	this.data.timeTo.attachHelpers({
		'TimeInput': {
			dateNamespace: 'to',
			showHours: true
		}
	});
	this.data.timeTo.getHelper('TimeInput').data.namespace = 'dateinput';
	
	// set date 30 min or 60 min for this day
	if(this.data.dateFrom.getValue().getMinutes() > 30) {
		this.data.dateFrom.getValue().setMinutes(60);
		this.data.dateTo.getValue().setMinutes(90);
	} else {
		this.data.dateFrom.getValue().setMinutes(30);
		this.data.dateTo.getValue().setMinutes(60);
	}
};
// Handlers
PuiInputDateTime.prototype.onChangeHandler = function (event, trigger) {
	var helper = null;
	switch (trigger){
		case 'dateFrom':
			var date = this.data.dateFrom.getValue().clone();
			date.setMinutes(date.getMinutes() + 30);
			this.data.dateTo.setValue(date);
			this.data.timeFrom.setValue();
			this.data.timeTo.setValue();
			var limitDate = date.clone();
			limitDate.setHours(limitDate.getHours() + 47);
			this.data.dateTo.getHelper('DateInput').data.limitDate = limitDate;			
		break;
		
		case 'timeFrom':	
			var date = this.data.dateFrom.getValue().clone();
			date.setMinutes(date.getMinutes() + 30);
			this.data.dateTo.setValue(date);
			this.data.timeTo.setValue();
			helper  = this.data.timeFrom.getHelper('TimeInput');
		break;
		
		case 'dateTo':
			var dateFrom = this.data.dateFrom.getValue();
			var dateTo = this.data.dateTo.getValue();
			
			if(dateTo < dateFrom) {
				var date = dateTo.clone();
				date.setMinutes(date.getMinutes() - 30);
				this.data.dateFrom.setValue( date );
				var limitDate = date.clone();
				limitDate.setHours(limitDate.getHours() + 47);
				this.data.dateTo.getHelper('DateInput').data.limitDate = limitDate;
			}
			this.data.timeTo.setValue();
			this.data.timeFrom.setValue();			
		break;
		
		case 'timeTo':
			this.data.dateTo.setValue();
			helper  = this.data.timeTo.getHelper('TimeInput');
		break;	
	}
	if (null != helper && isDefined( helper.data.time )){ //data.time is PuiTime type
		// clear helper	
		helper.data.time.destroy();
		helper.data.window.destroy();
		delete(helper.data.time);
		delete(helper.data.window);
	}	
	
};
// Functions
PuiInputDateTime.prototype.getValue = function () {
	var dateFrom = this.data.dateFrom.getValue().getTime();
	var dateTo = this.data.dateTo.getValue().getTime();
	
	return {
		dateFrom: dateFrom,
		dateTo: dateTo
	};
};
PuiInputDateTime.prototype.setValue = function ( data ) {
	if(data) {
		this.data.dateFrom.getValue().setTime(data.dateFrom);
		this.data.dateTo.getValue().setTime(data.dateTo);
	}
	
	// set values
	this.data.dateFrom.setValue();
	this.data.dateTo.setValue();
	this.data.timeFrom.setValue();
	this.data.timeTo.setValue();
};
PuiInputDateTime.prototype.setDisabled = function ( bool ) {
	this.data.disabled = bool;
	this.data.dateFrom.setDisabled( bool );
	this.data.dateTo.setDisabled( bool );
	this.data.timeFrom.setDisabled( bool );
	this.data.timeTo.setDisabled( bool );
};
PuiInputDateTime.prototype.reset = function () {
	this.data.dateFrom.domEl.val('');
	this.data.dateTo.domEl.val('');
	this.data.timeFrom.domEl.val('');
	this.data.timeTo.domEl.val('');
};

/*

	--- Component: PuiInputVenueOrLocation ---
	
	Options:
		- venueInput
		- venueUrl
		- locationInput
		- locationUrl
		
*/
var PuiInputVenueOrLocation = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ) || !isDefined(this.options.venueInput) || !isDefined(this.options.locationInput))
		logError( 'No options', 'PuiInputVenueOrLocation', 'constructor' );

	this.data = {
		namespace: 'venueorlocation',
		callback: this.options.callback
	};
	PuiInputVenueOrLocation.superclass.constructor.call( this, this.data );
	// custom setup for this class only
	this._setup();
}
// Extends: PuiComponentInputAbstract
extend( PuiInputVenueOrLocation, PuiComponentAbstract );
// Setup 
PuiInputVenueOrLocation.prototype._setup = function () {
	// setup custom rows
	this.data.rows = [
		{
			id: 'custom-1',
			name_bold: 'Nav precīzas norises vietas',
			description: ''
		},
		{
			id: 'custom-2',
			name_bold: 'Pievienot jaunu vietu',
			description: ''
		}
	];
	// setup venue autocomplete
	var that = this;
	this.data.venue = new PuiInputText({
		id: this.options.venueInput,
		events: {
			'focus': function ( event ) {
				that.onVenueFocusHandler( event );
			},
			'blur': function ( event ) {
				that.onVenueBlurHandler( event );
			},
			'keydown': function ( event ) {
				that.onVenueKeyDownHandler( event );
			}
		}
	});
	this.data.venue.attachHelpers({
		'AutocompleteInput': {
			url: this.options.venueUrl,
			callback: that.data.callback,
			customRows: that.data.rows,
			onCustomSelect: function( row ) {
				that.onCustomSelectHandler( row.id );
			}
		},
		'DescriptionInner': {
			text: "Sāc rakstīt ēkas, iestādes, objekta nosaukumu..."
		}
	});
	// setup location autocomplete
	this.data.location = new PuiInputText({
		id: this.options.locationInput
	});
	this.data.location.attachHelpers({
		'AutocompleteInput': {
			url: this.options.locationUrl,
			params: {exclude: 7},
			callback: that.data.callback
		},
		'DescriptionInner': {
			text: "Sāc rakstīt pilsētas, pilsētas daļas, novada, pagasta vai ciema nosaukumu..."
		}
	});
	
	this.data.location.setVisible( false );
	
	this.domEl = this.data.venue.domEl;
};
// Functions
PuiInputVenueOrLocation.prototype.getValue = function () {
	var venue = this.data.venue.getValue();
	var location = this.data.location.getValue();

	if(venue) {
		return venue;
	} else if(location) {
		return location;
	} else return false;
};
PuiInputVenueOrLocation.prototype.setValue = function ( data ) {

	if( data ){
		if(isDefined(data['location'])) {
			this.onCustomSelectHandler('custom-1');
			this.data.location.setValue(data.location);
			if(isFunction(this.data.callback))
				this.data.callback(data.location);
		}
		// Model_Row_Event::toArrayJson()
		else if(isDefined(data['venue'])) {
			if(isDefined(this.data.customEl)){
				this.data.customEl.unbind();
				this.data.customEl.remove();
				delete(this.data.customEl);
			}
			
			this.data.location.getHelper('AutocompleteInput').destroyPick();
			this.data.location.setFocus(false);
			this.data.location.setVisible( false );
			//console.log(this.data.venue);abc
			this.data.venue.setValue(data.venue); // PuiInputText
			this.data.active = '';
			
			if(isFunction(this.data.callback)){
				this.data.callback(data.venue); // resolve-portal
			}
		}
	}
};
PuiInputVenueOrLocation.prototype.setDisabled = function ( bool ) {
	this.data.disabled = true;
	var value = this.getValue();
	
	if(this.data.active == 'location'){
		this.data.location.setDisabled(bool);
		this.data.location.getHelper('AutocompleteInput').data.pick.setDisabled( bool );
		if( bool ) {
			if(isDefined(this.data.customEl))
				this.data.customEl.find('span').addClass('pui-hidden');
		} else { 
			if(isDefined(this.data.customEl))
				this.data.customEl.find('span').removeClass('pui-hidden');
		}
	} else {
		this.data.venue.setDisabled(bool);
		if(isDefined(this.data.venue.getHelper('AutocompleteInput').data.pick))
			this.data.venue.getHelper('AutocompleteInput').data.pick.setDisabled( bool )
	};
};
PuiInputVenueOrLocation.prototype.reset = function () {
	if(isDefined(this.data.customEl)){
		this.data.customEl.unbind();
		this.data.customEl.remove();
		delete(this.data.customEl);
	}
	
	// clear location
	this.data.location.getHelper('AutocompleteInput').destroyPick();
	this.data.location.setFocus(false);
	this.data.location.setVisible( false );
	
	// clear venue
	this.data.venue.getHelper('AutocompleteInput').destroyPick();
	this.data.venue.setVisible( true );
	this.data.venue.setFocus( false );
};
// Handlers
PuiInputVenueOrLocation.prototype.onVenueFocusHandler = function ( event ) {
	if(isDefined(this.data.list)){
		this.data.list.destroy();
		delete(this.data.list);
	}
	var that = this;
	this.data.list = new PuiInputList({
		onSelect: function ( row ) {
			that.onCustomSelectHandler( row.id );
		}
	});
	if(!isDefined(this.data.window)) {
		this.data.window = new PuiWindow({
			version: 3
		});
	}
	this.data.list.setRows(this.data.rows);
	this.data.window.setContent( this.data.list );
	
	alignTo(this.data.window.domEl, this.data.venue.domEl, {
		align: "bottom left",
		alignPoint: "top left",
		offsetTop: 1,
		offsetLeft: 9
	});
	sizeTo(this.data.window.domEl, this.data.venue.domEl);
	
	this.data.window.setVisible( true );
};
PuiInputVenueOrLocation.prototype.onVenueBlurHandler = function ( event ) {
	if(isDefined(this.data.window)) {
		this.data.window.setVisible( false );
		this.data.list.destroy();
	}
};
PuiInputVenueOrLocation.prototype.onVenueKeyDownHandler = function ( event ) {
	if(isDefined(this.data.window) && this.data.window.isVisible()) {
		this.data.window.setVisible( false );
		this.data.list.destroy();
	}
};
PuiInputVenueOrLocation.prototype.onCustomSelectHandler = function ( strCustom ) {
	this.onVenueBlurHandler();
	that = this;
	if( strCustom == 'custom-1'){
		// setup custom element
		if(!isDefined(this.data.customEl)) {
			this.data.customEl = jQuery('<div></div>');
			this.data.customEl.html('Nav precīzas norises vietas <span>(<a class="pui-switch" href="#">mainīt</a>)</span>');
			this.data.customEl.insertBefore(this.data.location.domEl);
		
			// attach switch event
			var that = this;
			this.attachEvents(this.data.customEl.find('a'), {
				'click': that.onSwitchHandler
			});
		}
		
		// swtich inputs
		this.data.venue.getHelper('AutocompleteInput').destroyPick();
		this.data.venue.setVisible( false );
		this.data.venue.setFocus( false );
		this.data.location.setVisible( true );
		//this.data.location.setFocus( true );
		this.data.active = 'location';
	} else if( strCustom == 'custom-2') {
		this.data.suggestVenue = new PuiHelperSuggestVenue({
			venueOrLocation: this,
			title: "Pievienot jaunu vietu",
			callback: function(d){ // ko izpildiit peec save
			
				that.setValue({venue: d});
			}
		});
	}
};
PuiInputVenueOrLocation.prototype.onSwitchHandler = function ( event ) {
	event.preventDefault();
	this.data.customEl.unbind();
	this.data.customEl.remove();
	delete(this.data.customEl);
	
	this.data.location.getHelper('AutocompleteInput').destroyPick();
	this.data.location.setVisible( false );
	this.data.venue.setVisible( true );
	this.data.venue.setFocus( true );
	this.data.active = '';
};

/*

	--- Component: PuiCarousel ---
	
	Options:

		
*/
var PuiCarousel = function(options)
{
    var that = this;
    this.options = options;
    this.options.animationSpeed = 900;
    this.options.slideSpeed = 7000;
    this.options.elementWidth = 497;
    this.list = $(this.options.carousel.find('ul'));
    this.items = this.options.carousel.find('li');
    this.currentSlide = 0;
    this.animationInProgress = false;
    this.buttons = [];
    
    if(this.items.length > 1){
        for(var i = 1; i< this.items.length; ++i){
           $(this.items[i]).detach();
        }
        
        var a = $('<a href="#" class="pui-carousel-button-previous"></a>');
        a.click(function(event){
            event.preventDefault();
            if(!that.animationInProgress){
                that.previous();
                clearInterval(that.timer);
                that.timer = setInterval(that.rotate, that.options.slideSpeed);
            }
        });
        a.appendTo(this.options.buttonContainer);

        for(var i=0; i < this.items.length; ++i){
            var a = $('<a href="#" id="pui-carousel-previous"  class="pui-carousel-button"></a>');
            a.attr('data-move-to-slide', i);
            
            if(i == 0)
                a.addClass('pui-active');
            
            a.appendTo(this.options.buttonContainer);
            a.click(function(event){
                event.preventDefault();
                var slide = $(this).attr('data-move-to-slide');
                if(slide != that.currentSlide && !that.animationInProgress){
                    that.goTo(slide);
                    clearInterval(that.timer);
                    that.timer = setInterval(that.rotate, that.options.slideSpeed);
                }
            });
            this.buttons.push(a);
        }
        
        var a = $('<a href="#" id="pui-carousel-next" class="pui-carousel-button-next"></a>');
        a.click(function(event){
            event.preventDefault();
            if(!that.animationInProgress){
                that.next();
                clearInterval(that.timer);
                that.timer = setInterval(that.rotate, that.options.slideSpeed);
            }
        });
        a.appendTo(this.options.buttonContainer);

        // timer
       	this.timer = setInterval(this.rotate, this.options.slideSpeed);
        // setup mouseenter mouseleave
        var that = this;
        this.options.carousel.bind('mouseenter', function (event) {
        	//console.log('mouse enter');
			clearInterval(that.timer);
        });
        this.options.carousel.bind('mouseleave', function (event) {
        	//console.log('mouse leave');
        	clearInterval(that.timer);
			that.timer = setInterval(that.rotate, that.options.slideSpeed);
        });
    }
};
PuiCarousel.prototype.goTo = function(slide, to)
{
    var that = this;
    slide = parseInt(slide);

    if((slide > this.currentSlide || to == 'right') && to != 'left'){
        jQuery(this.items[slide]).insertAfter(this.items[this.currentSlide]);
        this.animationInProgress = true;
        this.options.carousel.animate({marginLeft: ['-', this.options.elementWidth, 'px'].join('')}, {
            duration:this.options.animationSpeed,
            complete: function(){
                that.options.carousel.css({marginLeft: '0px'});
                jQuery(that.items[that.currentSlide]).detach();
                that.currentSlide = slide;
                that.animationInProgress = false;
            }
        });
    }
    
    else if(slide < this.currentSlide || to == 'left'){
       	jQuery(this.items[slide]).insertBefore(this.items[this.currentSlide]);
        this.animationInProgress = true;
        that.options.carousel.css({marginLeft: '-497px'});
        this.options.carousel.animate({marginLeft: ['0px'].join('')}, {
            duration:this.options.animationSpeed,
            complete: function(){
                jQuery(that.items[that.currentSlide]).detach();
                that.currentSlide = slide;
                that.animationInProgress = false;
            }
        });
    }
    
    $.each(this.buttons, function(key, value){
        value.removeClass('pui-active');
    });
    this.buttons[slide].addClass('pui-active');
};
PuiCarousel.prototype.next = function()
{
    var slide = this.currentSlide + 1;
    if(slide == this.items.length)
        slide = 0;
        
    this.goTo(slide, 'right');
};
PuiCarousel.prototype.previous = function()
{
    var slide = this.currentSlide - 1;
    if(slide < 0)
        slide = this.items.length - 1;
        
    this.goTo(slide, 'left');
};
PuiCarousel.prototype.rotate = function(){
	jQuery('#pui-carousel-next').click();
};


/* PuiMap */

var PuiMap = function(input)
{
    this.input = input;
    var myLatlng = new google.maps.LatLng(57.53489,25.42411);
    var myOptions = {
            zoom: 13,
            center: myLatlng,
            mapTypeId: google.maps.MapTypeId.ROADMAP
    }

    this.map = new google.maps.Map(input[0], myOptions);
};

PuiMap.prototype.setMarker = function(coords, callback)
{
    
  // Add markers to the map
  // Marker sizes are expressed as a Size of X,Y
  // where the origin of the image (0,0) is located
  // in the top left of the image.

  // Origins, anchor positions and coordinates of the marker
  // increase in the X direction to the right and in
  // the Y direction down.
  var image = new google.maps.MarkerImage('/cssv1/map_icon_flag.png',
      // This marker is 20 pixels wide by 32 pixels tall.
      new google.maps.Size(28, 38),
      // The origin for this image is 0,0.
      new google.maps.Point(0,0),
      // The anchor for this image is the base of the flagpole at 0,32.
      new google.maps.Point(0, 38));
  var shadow = new google.maps.MarkerImage('/cssv1/map_icon_flag_shadow.png',
      // The shadow image is larger in the horizontal dimension
      // while the position and offset are the same as for the main image.
      new google.maps.Size(28, 38),
      new google.maps.Point(0,0),
      new google.maps.Point(0, 38));
      // Shapes define the clickable region of the icon.
      // The type defines an HTML <area> element 'poly' which
      // traces out a polygon as a series of X,Y points. The final
      // coordinate closes the poly by connecting to the first
      // coordinate.
  var shape = {
      coord: [1, 1, 1, 38, 28, 38, 28 , 1],
      type: 'poly'
  };

  var marker = new google.maps.Marker({
        position: coords,
        map: this.map,
        draggable:true,
        shadow: shadow,
        icon: image,
        shape: shape
      });

    marker;

    google.maps.event.addListener(marker, 'dragend', function(){
        callback(marker);
    });
    
    return marker;
}

/* ------------------ PuiInputCoordinates ------------ */

var PuiInputCoordinates = function(options)
{
    var that = this;
    this.options = options;
    this.input = this.options.input;
    this.map = new PuiMap(this.input);
    this.marker = false;
    this.lastSetAddress = false;
    
    this.data = {
    	namespace: 'coordinatesinput'
    }
    
    var myLatlng = new google.maps.LatLng(57.53489,25.42411);
    
    google.maps.event.addListener(this.map.map, 'click', function(event) {
    	that.marker.setPosition(event.latLng);
  	});
};
PuiInputCoordinates.prototype.positionMapByLocationName = function(data)
{
    var that = this;
    
    var Geocoder = new google.maps.Geocoder();
    Geocoder.geocode({
        address: data.name
    }, function(result, status){
        if(isDefined(result[0]))
            that.positionMap(result[0].geometry.location);
        else {
            Geocoder.geocode({
                address: data.description
            }, function(result, status){
                if(isDefined(result[0]))
                    that.positionMap(result[0].geometry.location);
            });
        }
    });
}
PuiInputCoordinates.prototype.positionMap = function(latLng)
{
    var that = this;
    this.map.map.setCenter(latLng);
    if(isDefined(that.options.inputForLat))
        that.options.inputForLat.val(latLng.lat());

    if(isDefined(that.options.inputForLong))
        that.options.inputForLong.val(latLng.lng());
    
    if(!this.marker)
        this.marker = this.map.setMarker(latLng, function(marker){
            var Geocoder = new google.maps.Geocoder();
            Geocoder.geocode({
                latLng: marker.position
            }, function( result, status ){
                // if(isDefined(that.options.inputForAddress) && (that.options.inputForAddress.val() == '' || that.options.inputForAddress.val() == that.lastSetAddress)){
                    // that.options.inputForAddress.val([result[0].address_components[1].long_name, result[0].address_components[0].long_name].join(' '));
                    // that.lastSetAddress = that.options.inputForAddress.val();
                // }

                if(isDefined(that.options.inputForLat))
                    that.options.inputForLat.val(marker.position.lat());

                if(isDefined(that.options.inputForLong))
                    that.options.inputForLong.val(marker.position.lng());
            });
        });
    else this.marker.setPosition(latLng);
};
PuiInputCoordinates.prototype.getValue = function () {
	if(isDefined(this.marker) && isDefined(this.marker.position)){
		var hash = {};
		hash.lat = this.marker.position.lat();
		hash.lng = this.marker.position.lng();
		return hash;
	}
	
	return false;
};
PuiInputCoordinates.prototype.setErrors = function ( objErrors ) {
	// setup
	this.clearErrors();
	this.data.errors = {};
	this.data.errors.label = jQuery(['label[for="', objErrors.labelId, '"]'].join(''));
	this.data.errors.label.addClass('pui-error');
	this.data.errors.inputs = [];
	this.data.errors.messages = objErrors.messages;

	var that = this;
	jQuery.each(  objErrors.inputs, function ( key, value ) {
		if(value){
			var input = jQuery(['#', value].join(''));
			input.addClass('pui-error');
			that.data.errors.inputs.push(input);
		}
	});
	// display messages
	var that = this;

	jQuery.each(this.data.errors.messages, function(index, error){
		var element = jQuery('<span class="pui-input-description pui-error"></span>');
		element.html(error).appendTo(that.input.parent());
	});
};
PuiInputCoordinates.prototype.clearErrors = function () {
	if(isDefined(this.data.errors)){
		this.data.errors.label.removeClass('pui-error');
		jQuery.each( this.data.errors.inputs, function ( index, input ) {
			input.removeClass('pui-error');
		});
		this.input.parent().find('span.pui-error').remove();
		delete(this.data.errors);
	}
};

/*

	--- Component: PuiUploadQueue ---
	
	Options:
		
*/
var PuiUploadQueue = function ( objOptions ) {
	var that = this;
	this.options = objOptions;
		
	this.template = {
		name: 'upload',
		version: 'queue',
		partial: 'files'
	};

	this.data = {
		_fileLimit: 10,
		_sizeLimit: 1024 * 1024 * 5, // 5Mb
		fileLimit: function () {
			return this._fileLimit;
		},
		sizeLimit: function () {
			return this._sizeLimit.bytesConvert();
		}, 
		_rows: [],
		rows: function () {
			if(this._rows.length == 0)
				return false;
			
			return this._rows;
		},
		hasErrors: false,
		startUploadButton: this.options.startUploadButton
	};
	
	PuiUploadQueue.superclass.constructor.call( this, this.data );
	
	this._render();
};
// extend
extend( PuiUploadQueue, PuiComponentAbstract );
// callbacks
PuiUploadQueue.prototype._postRender = function () {
	this.data.renderPartialIn = this.domEl.find('.pui-file-list-container');
};
PuiUploadQueue.prototype._postRenderPartial = function () {
	var that = this;
	this.attachEvents( this.domElPartial.find('.pui-remove'), {
		'click': that.onFileRemove
	});
};
// functions
PuiUploadQueue.prototype.setStart = function ( swfFileObject ) {
	jQuery(['#', swfFileObject.id].join('')).find('.pui-remove').addClass('pui-hidden');
};
PuiUploadQueue.prototype.setFinish = function ( swfFileObject ) {
	jQuery(['#', swfFileObject.id].join('')).addClass('pui-success');
	jQuery(['#', swfFileObject.id].join('')).find('.pui-file-progress').css({
		'width': '100%'
	});
	jQuery(['#', swfFileObject.id].join('')).find('.pui-icon-8').removeClass('pui-hidden');
}; 
PuiUploadQueue.prototype.setProgress = function ( swfFileObject, percent ) {
	jQuery(['#', swfFileObject.id].join('')).find('.pui-file-progress').css({
		'width': [percent, '%'].join('')
	});
};
PuiUploadQueue.prototype.addRow = function ( swfFileObject ) {
	var hash = {};
	
	hash.id = swfFileObject.id;
	hash.name = swfFileObject.name;
	hash.size = swfFileObject.size.bytesConvert();
	hash.size_raw = swfFileObject.size;
	this.data._rows.push(hash);
	
	// calculate size
	var size = 0;
	
	jQuery.each(this.data._rows, function(index, row){
		size += row.size_raw;
	});
	
	// update status bar
	this.domEl.find('.pui-queue-files-count').html(this.data._rows.length);
	this.domEl.find('.pui-queue-size').html(size.bytesConvert());
	
	// check if there is limit errors
	if(this.data._rows.length > this.data._fileLimit) {
		this.domEl.find('.pui-queue-files-count').addClass('pui-error');
		this.data.hasErrors = true;
	}
		
	if(size > this.data._sizeLimit) {
		this.domEl.find('.pui-queue-size').addClass('pui-error');
		this.data.hasErrors = true;
	}
	
	if(this.data.hasErrors) {
		this.data.startUploadButton.setDisabled( true );
		hash.isAlert = true;
	}
};
// callbacks
PuiUploadQueue.prototype.onFileRemove = function (event) {
	event.preventDefault();
	var that = this;
	jQuery.each(this.data._rows, function( index, row ) {
		if(row.id == jQuery(event.currentTarget).closest('li').attr('id')) {
			that.data.swf.cancelUpload(row.id);
			jQuery(event.currentTarget).closest('li').remove();
			that.data._rows = jQuery.grep(that.data._rows, function ( n ) {
  				return  n != row;
			});
		}
	});
	
	// calculate size
	var size = 0;
	
	jQuery.each(this.data._rows, function(index, row){
		size += row.size_raw;
	});
	
	this.domEl.find('.pui-queue-files-count').html(this.data._rows.length);
	this.domEl.find('.pui-queue-size').html(size.bytesConvert());
	
	// check if there is limit errors
	if(this.data._rows.length <= this.data._fileLimit)
		this.domEl.find('.pui-queue-files-count').removeClass('pui-error');
		
	if(size <= this.data._sizeLimit)
		this.domEl.find('.pui-queue-size').removeClass('pui-error');
		
	if(size <= this.data._sizeLimit && this.data._rows.length <= this.data._fileLimit)
		this.data.hasErrors = false;
	
	if(!this.data.hasErrors) {
		this.data.startUploadButton.setDisabled( false );
		this.domEl.find('.pui-alert').removeClass('pui-alert');
	}
};

/*

	--- Component: PuiTooltip, Versions: Small, Big ---

*/
var tooltipContainer = new Array();

var PuiTooltip = function(options){
	this.options = options;
	this.target = null;
	this.element = null;
};
PuiTooltip.prototype.init = function(target)
{
	if(!isDefined(target))
		throw new Error('No target for tooltip');
	
	var that = this;
	this.visible = false;
	this.target = target;
	this.element = this.create();
	
	if(isDefined(this.options)){
		if(isDefined(this.options.onState)) {
			if(this.options.onState == 'hover')
				this.target.bind('mouseenter.tooltip', function(){
					that.show();
				}).bind('mouseleave.tooltip',function(){
					that.hide();
				});
			else if(this.options.onState == 'active'){
				
				this.target.bind('click.tooltip', function(event){
                     event.preventDefault();
     				jQuery.each(tooltipContainer, function(i,val){
     					tooltipContainer[i].target.removeClass('pui-active');
     					tooltipContainer[i].hide();
                    });
    				tooltipContainer = [];
    				tooltipContainer.push(that);
                     
					if(that.isVisible()){
						that.target.removeClass('pui-active');
						that.hide();
					} else {
						that.target.addClass('pui-active');
						that.show();
					}
				});
			}
		}
		
		// set title
		if(isDefined(this.options.title))
			this.setTitle(this.options.title);
		
		// set content
		if(isDefined(this.options.content))
			this.setContent(this.options.content);
	}
};
PuiTooltip.prototype.create = function(){
	throw new Error('You need to override this function');
};
PuiTooltip.prototype.position = function(){
	throw new Error('You need to override this function');
}
PuiTooltip.prototype.setTitle = function(string)
{
	this.element.find('.pui-title').html(string);
};
PuiTooltip.prototype.setContent = function(string)
{
	this.element.find('.pui-content').html(string);
};
PuiTooltip.prototype.show = function(){
	this.element.removeClass('pui-hidden');
	this.position();
};
PuiTooltip.prototype.hide = function(){
	this.element.addClass('pui-hidden');
};
PuiTooltip.prototype.isVisible = function(){
	return !this.element.hasClass('pui-hidden');
}

/* ------------- PuiTooltipSmall -------------- */
var PuiTooltipSmall = function(options){
	PuiTooltipSmall.superclass.constructor.call(this, options);
}
// extends PuiTooltip
extend(PuiTooltipSmall, PuiTooltip);
// overwrite PuiTooltip functions
PuiTooltipSmall.prototype.create = function(){ 
	var element = jQuery(['<div class="pui-tooltip pui-type-2 pui-hidden">', 
		                this.target.attr('data-description'),
		                '<span class="pui-pointer"></span></div>'].join('')).appendTo('body');
	return element;
};
PuiTooltipSmall.prototype.position = function()
{
	alignTo(this.element, this.target, {
		align: "top center",
		alignPoint: "bottom center",
		offsetTop: -15
	});
};

/* ------------- PuiTooltipBig -------------- */
// options
var PuiTooltipBig = function(options){
	PuiTooltipBig.superclass.constructor.call(this, options);
}
// extends PuiTooltip
extend(PuiTooltipBig, PuiTooltip);
// overwrite PuiTooltip functions
PuiTooltipBig.prototype.create = function()
{
	var that = this;
	var element = jQuery('<div class="pui-tooltip-container pui-hidden"><div class="pui-pointer"></div><div class="pui-tooltip pui-type-1"><div class="pui-header"><h4 class="pui-title">Header</h4><div class="pui-buttons"></div></div><hr/><div class="pui-content"><p>content</p></div></div></div>').appendTo('body');
	var closeButton = jQuery('<a class="pui-button pui-custom-2 pui-small" href="#"><span class="pui-icon pui-icon-1"></span></a>');
	
	closeButton.click(function(event){
		event.preventDefault();
		if(that.options.onState == 'active')
			that.target.removeClass('pui-active');
		that.hide();
	});
	closeButton.appendTo(element.find('.pui-buttons'));

	element.css({
		width: '300px',
		zIndex: '1000'
	});
	
	return element;
};
PuiTooltip.prototype.position = function()
{	
	alignTo(this.element, this.target, {
		align: "top right",
		alignPoint: "top left",
		offsetLeft: 22,
		offsetTop: -12
	});
};

/* 
	==========================================
	Pui component helpers
	==========================================
*/

/*

	--- Component: PuiHelperClearInput ---
	
	Options: 
		- component

*/
var PuiHelperClearInput = function ( objOptions ) {
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiHelperClearInput', 'constructor' );
	
	this.template = {
		name: 'helper',
		version: (isDefined(this.options.version)) ? this.options.version : 'clear'
	};
	this.data = {
		visible: false,
		events: {
			'click': this.onClickHandler
		},
		component: this.options.component,
		componentEvents: {
			'keyup': this.onKeyUpHandler,
		},
		namespace: 'clear'
	};
	PuiHelperClearInput.superclass.constructor.call( this, this.data );
	this._attach();
};
// Extends: PuiComponentHelperAbstract
extend( PuiHelperClearInput, PuiComponentHelperAbstract );
// Callback for: attach
PuiHelperClearInput.prototype._postAttach = function ()
{
	this.data.renderAfter = this.data.component.domEl;
	this._render();
	this.data.component.domEl.css({
		'padding-right': '22px',
		'width': [this.data.component.domEl.width() + parseInt(this.data.component.domEl.css('padding-left'), 10) - 25, 'px'].join('')
	});
	// set visible
	if(this.data.component.domEl.val().length > 0)
		this.setVisible( true );
};
// Component event handlers
PuiHelperClearInput.prototype.onKeyUpHandler = function (event) {
	this.setVisible( true );
};
// Helper event handlers
PuiHelperClearInput.prototype.onClickHandler = function (event) {
	event.preventDefault();
	this.data.component.domEl.val('');
	this.data.component.setFocus( true );
	this.setVisible( false );
};

/*

	--- Component: PuiHelperDescriptionInner ---
	
	Options: 
		- component

*/
var PuiHelperDescriptionInner = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiHelperDescriptionInner', 'constructor' );

	this.data = {
		text: (isDefined( this.options.text )) ? this.options.text : false,
		component: this.options.component,
		componentEvents: {
			'blur': that.onBlurHandler,
			'focus': that.onFocusHandler
		},
		namespace: 'description'
	};
	PuiHelperDescriptionInner.superclass.constructor.call( this, this.data );
	
	this._attach();
};
// Extends: PuiComponentHelperAbstract
extend( PuiHelperDescriptionInner, PuiComponentHelperAbstract );
// Callback to: attach
PuiHelperDescriptionInner.prototype._postAttach = function () {
	this.setComponentValue();
};
// Event: handlers
PuiHelperDescriptionInner.prototype.onBlurHandler = function (event) {
	if(this.data.component.isFocus())
		this.data.component.setFocus( false );
	this.setComponentValue();
};
PuiHelperDescriptionInner.prototype.onFocusHandler = function (event) {
	this.setComponentValue();
};
PuiHelperDescriptionInner.prototype.setComponentValue = function () {
	if(isString(this.options.text)){
		if(!this.data.component.domEl.val() && !this.data.component.isFocus()) {
			this.data.component.domEl.addClass('pui-description');
			this.data.component.domEl.val(this.data.text);
		}
		else if (this.data.component.domEl.val() == this.data.text) {
			this.data.component.domEl.val('');
			this.data.component.domEl.removeClass('pui-description');
		}
	}
	else logError('No text', 'PuiHelperDescriptionInner', 'setComponentValue');
};

/*

	--- Component: PuiHelperDateInput ---
	
	Options: 
		- component

*/
var PuiHelperDateInput = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiHelperDateInput', 'constructor' );

	this.data = {
		text: (isDefined( this.options.text )) ? this.options.text : false,
		component: this.options.component,
		componentEvents: {
			'blur': that.onBlurHandler,
			'focus': that.onFocusHandler
		},
		namespace: 'dateinput',
		dateNamespace: (isDefined( this.options.dateNamespace )) ? this.options.dateNamespace : 'default',
		calendar: null,
		limitDate: false
	};
	PuiHelperDateInput.superclass.constructor.call( this, this.data );
	
	this._attach();
};
// Extends: PuiComponentHelperAbstract
extend( PuiHelperDateInput, PuiComponentHelperAbstract );
// Callback to: attach, destroy
PuiHelperDateInput.prototype._postAttach = function () {
	this._getCache()
		.getNamespace( this.data.namespace )
		.set( this.data.dateNamespace, new Date() );
	// Overwrite
	var that = this;
	this.data.component.getValue = function () {
		return that._getCache().getNamespace(that.data.namespace).get(that.data.dateNamespace);
	};
	this.data.component.setValue = function ( objDate ) {
		if(isDefined(objDate))
			that._getCache().getNamespace(that.data.namespace).set(that.data.dateNamespace, objDate);
		that._getCache().getNamespace(that.data.namespace).get(that.data.dateNamespace).setDateAsElementValue(this.domEl);
	};
	// attach on change event
	this.attachEvents( this.data.component.domEl, {
		'change': that.onChangeHandler,
		'keydown': that.onBlurHandler
	});
};
PuiHelperDateInput.prototype._preDestroy = function () {
	this._getCache().clearNamespace(this.data.namespace);
};
// Event handlers for component
PuiHelperDateInput.prototype.onBlurHandler = function () {
	if(isDefined( this.data.calendar )) {
		this.data.calendar.destroy();
		this.data.window.destroy();
		delete(this.data.calendar);
		delete(this.data.window);
	}
};
PuiHelperDateInput.prototype.onFocusHandler = function () {
	var that = this;
	this.data.calendar = new PuiCalendar({
		date: this._getCache().getNamespace(this.data.namespace).get(this.data.dateNamespace),
		onSelect: function ( objDate ) {
			that.data.component.domEl.removeClass('pui-error');
			that._getCache()
				.getNamespace( that.data.namespace )
				.set( that.data.dateNamespace, objDate );
			that.data.component.setValue( objDate );
			that.data.component.setFocus( false );
		},
		version: 1,
		limitDate: this.data.limitDate
	});
	this.data.window = new PuiWindow({
		version: 3
	});
	this.data.window.setContent( this.data.calendar );
	alignTo(this.data.window.domEl, this.data.component.domEl, {
		align: "bottom left",
		alignPoint: "top left",
		offsetTop: 1,
		offsetLeft: 9
	});
	this.data.window.setVisible( true );
};
PuiHelperDateInput.prototype.onChangeHandler = function (event) {
	var chunks = this.data.component.domEl.val().split('.');
	
	var day = chunks[0];
	var month = chunks[1];
	var year = chunks[2];
	
	var date = new Date(year, month, day);

	if(isNaN(date.getDate())){
		this.data.component.domEl.addClass('pui-error');
	}
	else {
		this.data.component.domEl.removeClass('pui-error');
		this._getCache()
		.getNamespace( this.data.namespace )
		.set( this.data.dateNamespace, date );
	}
}

/*

	--- Component: PuiHelperTimeInput ---
	
	Options: 
		- component

*/
var PuiHelperTimeInput = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiHelperTimeInput', 'constructor' );

	this.data = {
		text: (isDefined( this.options.text )) ? this.options.text : false,
		component: this.options.component,
		componentEvents: {
			'blur': that.onBlurHandler,
			'focus': that.onFocusHandler
		},
		namespace: 'timeinput',
		dateNamespace: (isDefined( this.options.dateNamespace )) ? this.options.dateNamespace : 'default',
		showHours: (isDefined(this.options.showHours)) ? this.options.showHours : false
	};
	PuiHelperTimeInput.superclass.constructor.call( this, this.data );
	
	this._attach();
};
// Extends: PuiComponentHelperAbstract
extend( PuiHelperTimeInput, PuiComponentHelperAbstract );
PuiHelperTimeInput.prototype._postAttach = function () {
	this._getCache()
		.getNamespace( this.data.namespace )
		.set( this.data.dateNamespace, new Date() );
	
	var that = this;
	this.data.component.setValue = function ( objDate ) {
		if(isDefined(objDate))
			that._getCache().getNamespace(that.data.namespace).set(that.data.dateNamespace, objDate);
		that._getCache().getNamespace(that.data.namespace).get(that.data.dateNamespace).setTimeAsElementValue(this.domEl);
	};
	
	// attach on change event
	this.attachEvents( this.data.component.domEl, {
		'change': that.onChangeHandler,
		'keydown': that.onBlurHandler
	});
};
// Event handlers for component
PuiHelperTimeInput.prototype.onBlurHandler = function () {};// do not delete
PuiHelperTimeInput.prototype.onFocusHandler = function () {
	var that = this;
	var date = this._getCache().getNamespace(this.data.namespace).get(this.data.dateNamespace).clone();
	if(this.data.dateNamespace == 'to')
		date.setMinutes(date.getMinutes() - 30);
	this.data.time = new PuiTime({
		date: date,
		onSelect: function ( objDate ) {
			that.data.component.domEl.removeClass('pui-error');
			that._getCache()
				.getNamespace( that.data.namespace )
				.set( that.data.dateNamespace, objDate );
			that.data.component.setValue( objDate );
			that.data.component.setFocus( false );
		},
		showHours: that.data.showHours
	});
	this.data.window = new PuiWindow({
		version: 3,
		height: 200
	});
	this.data.window.setContent( this.data.time );
	alignTo(this.data.window.domEl, this.data.component.domEl, {
		align: "bottom left",
		alignPoint: "top left",
		offsetTop: 1,
		offsetLeft: 9
	});
	this.data.window.setVisible( true );
};
PuiHelperTimeInput.prototype.onChangeHandler = function (event) {
	var date = this._getCache().getNamespace(this.data.namespace).get(this.data.dateNamespace).clone();
	var hours = this.data.component.domEl.val().split(':').shift();
	var minutes = this.data.component.domEl.val().split(':').pop();
	date.setHours(hours);
	date.setMinutes(minutes);

	if(isNaN(date.getDate()) || (parseInt(hours) > 23 && parseInt(minutes) > 59)){
		this.data.component.domEl.addClass('pui-error');
	}
	else {
		this.data.component.domEl.removeClass('pui-error');
		this._getCache()
		.getNamespace( this.data.namespace )
		.set( this.data.dateNamespace, date );
	}
}

/*

	--- Component: PuiHelperAutocompleteInput ---
	
	Options: 
			url:		string, E.g.'/calendar/venues/locations',
			params:		obj. E.g. {exclude: 7},
			callback:	function (row) - Optional.
			onSelect:	function (row) - Optional. Ja nav shis, izpilda this.createPick
*/
var PuiHelperAutocompleteInput = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiHelperAutocompleteInput', 'constructor' );

	this.template = {
		name: 'autocomplete',
		version: 1
	};

	this.data = {
		url: (isDefined( this.options.url )) ? this.options.url : false,
		params: (isDefined(this.options.params)) ? this.options.params : {},
		text: (isDefined( this.options.text )) ? this.options.text : false,
		component: this.options.component,
		componentEvents: {
			'keyup': that.onKeyUpHandler,
			'blur': that.onBlurHandler
		},
		visible: false,
		pickVersion: (isDefined(this.options.pickVersion)) ? this.options.pickVersion : 'pick',
		onSelect: (isDefined(this.options.onSelect)) ? this.options.onSelect : false,
		callback: (isDefined(this.options.callback)) ? this.options.callback : false,
		customRows: (isDefined(this.options.customRows)) ? this.options.customRows : false,
		onCustomSelect: (isDefined(this.options.onCustomSelect)) ? this.options.onCustomSelect : false
	};
	PuiHelperAutocompleteInput.superclass.constructor.call( this, this.data );
	
	this._render();
	this._attach();
};
// Extends: PuiComponentHelperAbstract
extend( PuiHelperAutocompleteInput, PuiComponentHelperAbstract );
// post render
PuiHelperAutocompleteInput.prototype._postRender = function () {
	this.domEl.insertAfter( this.data.component.domEl );
	// disable browser autocomplete
	this.data.component.domEl.attr('autocomplete', 'off');
	// create hidden input to store autocomplete pick
	var a = jQuery('#'+this.data.component.data.id+'_id');
	if (a.length > 0 )
		this.data.hiddenInput = a;
	else{
		this.data.hiddenInput = jQuery('<input type="hidden"/>');
		this.data.hiddenInput.attr('id', this.data.component.data.id+'_id');
		this.data.hiddenInput.attr('name', this.data.component.data.id+'_id');
		this.data.hiddenInput.appendTo(this.data.component.domEl.parent());
	}
};
// Post attach callback
PuiHelperAutocompleteInput.prototype._postAttach = function () {
	var that = this;
	// overwrite 
	this.data.component.getValue = function () {
		if(that.data.hiddenInput.val()){
			var hash = {};
			hash[that.data.component.domEl.attr('id')] = that.data.hiddenInput.val();
			return hash;
		}
		return false;
	};
	this.data.component.setValue = function ( row ) {
		if( row )
			that.createPick( row );
	};
};
// Handlers
PuiHelperAutocompleteInput.prototype.onKeyUpHandler = function ( event ) {
	if(jQuery.inArray( event.keyCode, [38, 40, 13, 37, 39, 16, 9, 17, 18, 91]) > -1 || !this.data.url || this.isBusy())
		return false;
	
	this.request();
};
PuiHelperAutocompleteInput.prototype.onBlurHandler = function ( event ) {
	if(isDefined( this.data.list )) {
		this.data.list.destroy();
		this.data.window.destroy();
		delete(this.data.list);
		delete(this.data.window);
	}
};
// functions
PuiHelperAutocompleteInput.prototype.request = function () {
	this.setBusy( true );
	this.setVisible( true );
	
	this.data.params['needle'] = this.data.component.domEl.val();
	
	var that = this;
	jQuery.get( this.data.url, this.data.params, function ( json ) {
		that.setBusy( false );
		that.setVisible( false );
		if(json.status == 1) {
			if(isDefined(that.data.list)){
				that.data.list.destroy();
				delete(that.data.list);
			}
			that.data.list = new PuiInputList({
				onSelect: function ( row ) {
					
					if(row.id.indexOf('custom') > -1) {
						that.data.window.destroy();
						return that.data.onCustomSelect( row );
					}
					
					if(isFunction(that.data.onSelect)){
						that.data.onSelect(row);
					}
					else 
						that.createPick( row );
					
					if(isFunction(that.data.callback))
						that.data.callback(row);
				}
			});
			if(!isDefined(that.data.window)) {
				that.data.window = new PuiWindow({
					version: 3,
					height: 300
				});
			}
			
			// append custom rows if there is data
			if(isDefined(that.data.customRows) && that.data.customRows.length > 0) {
				jQuery.each(that.data.customRows, function ( index, row ) {
					json.rows.push(row);
				});
			}
			
			that.data.list.setRows(json.rows);
			that.data.window.setContent( that.data.list );
			
			if(that.data.component.domEl.css('margin-left') == '0px')
				var offsetLeft = 9;
			else var offsetLeft = 0;
			
			alignTo(that.data.window.domEl, that.data.component.domEl, {
				align: "bottom left",
				alignPoint: "top left",
				offsetTop: 1,
				offsetLeft: offsetLeft
			});
			sizeTo(that.data.window.domEl, that.data.component.domEl);
			
			that.data.window.setVisible( true );
		} else {
			if(isDefined(that.data.list)){
				that.data.list.destroy();
				delete(that.data.list);
			}
			that.data.list = new PuiInputList({
				onSelect: function ( row ) {
					if(row.id.indexOf('custom') > -1) {
						that.data.window.destroy();
						return that.data.onCustomSelect( row );
					}
					
					that.data.component.setFocus( false );
					that.data.hiddenInput.val( row.id );
					if(isDefined(that.data.window))
						that.data.window.setVisible( false );
				}
			});
			if(!isDefined(that.data.window)) {
				that.data.window = new PuiWindow({
					version: 3
				});
			}
			
			var rows = [{
				uuid: 'notfound',
				name: 'Nekas netika atrasts'
			}];
			// append custom rows if there is data
			if(isDefined(that.data.customRows) && that.data.customRows.length > 0) {
				jQuery.each(that.data.customRows, function ( index, row ) {
					rows.push(row);
				});
			}
			
			that.data.list.setRows(rows);
			that.data.window.setContent( that.data.list );
			
			alignTo(that.data.window.domEl, that.data.component.domEl, {
				align: "bottom left",
				alignPoint: "top left",
				offsetTop: 1,
				offsetLeft: 9
			});
			sizeTo(that.data.window.domEl, that.data.component.domEl);
			
			that.data.window.setVisible( true );
		}
	} );
};
/**
 * Row object properties:
 * 		row.name
 * 		row.description
 */
PuiHelperAutocompleteInput.prototype.createPick = function ( row ) {

	this.destroyPick();
	var that = this;
	this.data.pick = new PuiAutocompletePick({
		name: row.name,
		description: row.description,
		onRemove: function () {
			that.destroyPick();
		},
		version: this.data.pickVersion
	});
	that.data.hiddenInput.val( row.id );
	this.data.component.setVisible( false );
	that.data.component.setFocus( false );
	this.data.component.setValue( '' );
	this.data.pick.domEl.insertAfter(this.data.component.domEl);
	sizeTo(this.data.pick.domEl, this.data.component.domEl);
};
PuiHelperAutocompleteInput.prototype.destroyPick = function () {
	if(isDefined(this.data.pick))
		this.data.pick.destroy();
	this.data.component.setVisible( true );
	this.data.component.setFocus( true );
	this.data.hiddenInput.val( '' );
	this.data.component.domEl.val( '' );
};

/*

	--- Component: PuiHelperTimeInput ---
	
	Options: 
		- component

*/
var PuiHelperWysiwyg = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ))
		logError( 'No options', 'PuiHelperWysiwyg', 'constructor' );

	this.data = {
		component: this.options.component,
		componentEvents: false,
		namespace: 'wysiwyg',
		disabled: (isDefined(this.options.disabled)) ? this.options.disabled : false
	};
	PuiHelperWysiwyg.superclass.constructor.call( this, this.data );
	
	this._attach();
};
// Extends: PuiComponentHelperAbstract
extend( PuiHelperWysiwyg, PuiComponentHelperAbstract );
// Callbacks
PuiHelperWysiwyg.prototype._postAttach = function () {
	tinyMCE.init({
        mode : "none",
        theme : "advanced",
        plugins : "paste, embed, autoresize",
        // Theme options
        theme_advanced_buttons1 : "bold,italic,|,pastetext,pasteword,|,bullist,numlist,|,link,unlink, embed,|,undo,redo,code",
        theme_advanced_buttons2 : "",
        theme_advanced_buttons3 : "",
        theme_advanced_buttons4 : "",
        theme_advanced_buttons4 : "",
        theme_advanced_toolbar_location : "top",
        theme_advanced_toolbar_align : "left",
        theme_advanced_resizing : false
        //height:"241"
    });
    
    if(!this.data.disabled)
    	this.attachEditor();
    
    // Overwrite
    this.data.component.getValue = function () {
    	var hash = {};
    	if(tinyMCE.get(this.data.id))
    		hash[this.data.id] = tinyMCE.get(this.data.id).getContent();
    	else hash[this.data.id] = this.domEl.val();
    	return hash;
    };
	this.data.component.setValue = function ( data ) {
		if(isDefined(tinyMCE.get(this.data.id)))
			tinyMCE.get(this.data.id).setContent(data);
		else this.domEl.val(data);
	};
	this.data.component.setDisabled = function ( bool ) {
		this.data.disabled = bool;
		if( bool ) {
			this.getHelper('Wysiwyg').detachEditor();
			this.domEl.addClass('pui-disabled');
			this.domEl.attr('disabled', true);
		} else {
			this.getHelper('Wysiwyg').attachEditor();
			this.domEl.removeClass('pui-disabled');
			this.domEl.attr('disabled', false);
		}
	};
};
// functions
PuiHelperWysiwyg.prototype.attachEditor = function () {
	tinyMCE.execCommand('mceAddControl', false, this.data.component.domEl.attr('id'));
};
PuiHelperWysiwyg.prototype.detachEditor = function () {
	tinyMCE.execCommand('mceRemoveControl', true, this.data.component.domEl.attr('id'));
};

/*

	--- Component: PuiHelperSelectUpdateRelated ---
	
	Options: 
		- component

*/
var PuiHelperSelectUpdateRelated = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ) || !isDefined( this.options.relatedTo ) || !isDefined( this.options.url ))
		logError( 'No options', 'PuiHelperSelectUpdateRelated', 'constructor' );

	this.data = {
		url: this.options.url,
		relatedTo:  this.options.relatedTo,
		component: this.options.component,
		componentEvents: false,
		namespace: 'selectupdaterelated'
	};
	PuiHelperSelectUpdateRelated.superclass.constructor.call( this, this.data );
	
	this._attach();
};
// Extends: PuiComponentHelperAbstract
extend( PuiHelperSelectUpdateRelated, PuiComponentHelperAbstract );
// Callbacks
PuiHelperSelectUpdateRelated.prototype._postAttach = function () {
	// setup related select events
	var that = this;
	this.attachEvents( this.data.relatedTo.domEl, {
		'change': that.onRelatedChangeHandler
	} );
};
// Handlers
PuiHelperSelectUpdateRelated.prototype.onRelatedChangeHandler = function () {
	this.request();
};
PuiHelperSelectUpdateRelated.prototype.request = function () {
	this.data.component.setDisabled( true );
	
	var that = this;
	jQuery.post(this.data.url, {uuid: this.data.relatedTo.domEl.val()} , function ( json ) {
		if(json.status == 1) {
			if( !that.data.component.isVisible() ) {
				that.data.component.setVisible( true );
				that.data.component.domEl.closest('tr').removeClass('pui-hidden');
			}
				
			var rows = [];
			jQuery.each(json.rows, function ( index, row ) {
				rows.push({
					value: index,
					name: row
				});
			});
				
			that.data.component.setRows( rows );
			that.data.component.domEl.val('');
			that.data.component.setDisabled( false );
			that.data.component.domEl.closest('tr').removeClass('pui-hidden');
		} else if ( json.status == 0 ) {
			that.data.component.setVisible( false );
			that.data.component.domEl.closest('tr').addClass('pui-hidden');
		}
	} );
};

/*

	--- Component: PuiHelperImagesUpload ---
	
	Options: 
		- component

*/
var PuiHelperImagesUpload = function ( objOptions ) {
	var that = this;
	
	this.options = objOptions;
	if(!isDefined( objOptions ) || !isDefined( this.options.url ))
		logError( 'No options', 'PuiHelperImagesUpload', 'constructor' );

	this.data = {
		url: this.options.url,
		component: this.options.component,
		componentEvents: false,
		namespace: 'imagesupload',
		rows: []
	};
	
	PuiHelperImagesUpload.superclass.constructor.call( this, this.data );
	
	this._attach();
};
// Extends: PuiComponentHelperAbstract
extend( PuiHelperImagesUpload, PuiComponentHelperAbstract );
// Callbacks
PuiHelperImagesUpload.prototype._postAttach = function () {
	var that = this;
	// attach trigger button
	this.data.trigger = new PuiButton({
		id: 'pui-upload-trigger',
		label: "Pievienot",
		cssClass: "bold",
		renderIn: this.data.component.domEl,
		events: {
			'click': function ( event ) {
				that.onTriggerClickHandler( event );
			}
		}
	});
};
// Handlers
PuiHelperImagesUpload.prototype.onTriggerClickHandler = function ( event ) {
	event.preventDefault();
	var that = this;
	this.data.window = new PuiWindow({
		version: 2,
		title: "Bilžu pievienošana",
		buttons: [
			new PuiButton({
				id: 'pui-swf-trigger-cancel',
				label: "Atcelt",
				cssClass: "bold",
				events: {
					'click': function ( event ) {
						event.preventDefault();
						that.data.swf.stopUpload();
						that.data.window.destroy();
						//console.log('cancel upload');
					}
				}
			}),
			new PuiButton({
				id: 'pui-swf-trigger-start',
				label: "Augšuplādēt",
				cssClass: "pui-primary bold",
				events: {
					'click': function ( event ) {
						event.preventDefault();
						that.data.swf.startUpload();
						//console.log('start upload');
					}
				}
			})
		]
	});
	
	this.data.queue = new PuiUploadQueue({
		startUploadButton: that.data.window.data.buttons[0]
	});
	
	var message = new PuiMessage({
		version: 2,
		type: 'info',
		title: 'Augšuplādējamo attēlu skaits, izmēri un ierobežojumi',
		content: '<ul class="pui-bullet-points"><li>Atļautie formāti: jpg, png, gif (neanimēts);</li><li>Vienā reizē var pievienot 10 attēlus, ja to kopējais izmērs nepārsniedz 5 MB (megabaiti);</li><li>Netiks pievienoti attēli, kas pārsniedz 6000x6000 px izmēru un/vai 5 MB (megabaiti) izmēru.</li></ul>'
	});
	
	this.data.window.setMessage(message);
	this.data.window.setContent( this.data.queue );
	
	// setup swf
	this._setupSwf();
	this.data.queue.data.swf = this.data.swf;
	
	// show
	this.data.window.setVisible( true );
};
PuiHelperImagesUpload.prototype.onStartUploadHandler = function () {
	//console.log('start upload');
};
PuiHelperImagesUpload.prototype.onCancelUploadHandler = function () {
	//console.log('cancel upload');
};
// File add handlers
PuiHelperImagesUpload.prototype.onFileAddHandler = function ( swfFileObject ) {
	//console.log(this);
	this.data.queue.addRow( swfFileObject );
	//console.log('add file to queue');
};
PuiHelperImagesUpload.prototype.onFileAddErrorHandler = function ( swfFileObject, errorCode, message ) {
	//console.log('file queue error');
};
// File upload handlers
PuiHelperImagesUpload.prototype.onFileUploadStartHandler = function ( swfFileObject ) {
	this.data.queue.setStart( swfFileObject );
	//console.log('upload started');
};
PuiHelperImagesUpload.prototype.onFileUploadProgressHandler = function ( swfFileObject, bytesComplete, bytesTotal ) {
	var percent = Math.ceil((bytesComplete / bytesTotal) * 100);
	this.data.queue.setProgress( swfFileObject, percent );
};
PuiHelperImagesUpload.prototype.onFileUploadErrorHandler = function ( swfFileObject, errorCode, errorMsg ) {
	//console.log(errorMsg);
	//console.log('file has upload error');
};
PuiHelperImagesUpload.prototype.onFileUploadSuccessHandler = function ( swfFileObject, serverData, response ) {
	var json = jQuery.parseJSON(serverData);
	//console.log(json);
	if(json.status == 1){
		this.data.component.data._rows.push(json.row);
	}
};
PuiHelperImagesUpload.prototype.onFileUploadFinishHandler = function ( swfFileObject ) {
	this.data.queue.setFinish( swfFileObject );
	if (this.data.swf.getStats().files_queued > 0)
		this.data.swf.startUpload();
	else { 
		this.data.component._renderPartial();
		this.data.window.destroy();
	}
};
// Dialog handlers
PuiHelperImagesUpload.prototype.onDialogCompleteHandler = function ( numberOfFilesSelected, numberOfFilesQueued, totalNumberOfFilesInQueue ) {
	this.data.swf.setButtonImageURL('/ui/css/pui_swf_button_small.png');
	this.data.swf.setButtonDimensions(100, 19);
	jQuery('#pui-swf-container').css({
		left: "185px",
		top: "377px"
	});
	this.data.queue._renderPartial();
	//console.log('dialog complete');
};
// Functions
PuiHelperImagesUpload.prototype._setupSwf = function () {
   var that = this;
   var settings = {
        flash_url : "/ui/js/swfupload.swf",
        upload_url: this.data.url,
        file_size_limit : "5 MB",
        file_types : "*.jpg;*.gif;*.png",
        file_types_description : "Visi faili",
        file_upload_limit : 0,
        file_queue_limit : 10,
        custom_settings : {
                queue: this.queue
        },
        post_params: {
            puuid: that.data.component.data.form.data.uuid,
            ptype: 'event',
            sid: that.data.component.data.form.data.sessionId
        },
        debug: false,

        // Button settings
        button_image_url: "/ui/css/pui_swf_button_big.png",
        button_width: "208",
        button_height: "26",
        button_placeholder_id: "pui-swf-trigger",
        button_window_mode : SWFUpload.WINDOW_MODE.TRANSPARENT,

        // file add handlers
        file_queued_handler : function ( swfFileObject ) {
        	that.onFileAddHandler( swfFileObject );
        },
        file_queue_error_handler : function( swfFileObject, errorCode, message ) {
        	that.onFileErrorHandler( swfFileObject, errorCode, message );
        },
        // file upload handlers
        upload_start_handler : function ( swfFileObject ) {
        	that.onFileUploadStartHandler( swfFileObject );
        },
        upload_progress_handler : function ( swfFileObject, bytesComplete, bytesTotal ) {
        	that.onFileUploadProgressHandler( swfFileObject, bytesComplete, bytesTotal );
        },
        upload_error_handler : function ( swfFileObject, errorCode, errorMsg ) {
        	that.onFileUploadErrorHandler( swfFileObject, errorCode, errorMsg );
        },
        upload_success_handler : function ( swfFileObject, serverData, response ) {
        	that.onFileUploadSuccessHandler( swfFileObject, serverData, response );
        },
        upload_complete_handler : function ( swfFileObject ) {
        	that.onFileUploadFinishHandler( swfFileObject );
        },
        // dialog handler
        file_dialog_complete_handler : function ( numberOfFilesSelected, numberOfFilesQueued, totalNumberOfFilesInQueue ) {
        	that.onDialogCompleteHandler( numberOfFilesSelected, numberOfFilesQueued, totalNumberOfFilesInQueue );
        }
    };

	this.data.swf = new SWFUpload(settings);
};

/* 
	==========================================
	Pui form interactions
	==========================================
*/


/*

	--- Component: PuiHelperFormActionsEvent ---
	
	Options: 
		- component

*/
var PuiHelperFormActionsEvent = function ( objOptions ) {
	var that = this;
	this.options = objOptions;
	this.data = {};
	
	PuiHelperFormActionsEvent.superclass.constructor.call( this, this.options, this.data );
};
// Extends: PuiHelperFormActionsAbstract
extend( PuiHelperFormActionsEvent, PuiHelperFormActionsAbstract );
// Setup 
PuiHelperFormActionsEvent.prototype._setup = function () {
	if(this.data.component.data.status == 'creating') {
		this.data.component.getActionButton('Delete').setVisible( false );
		this.data.component.getActionButton('Edit').setVisible( false );
	} else if(this.data.component.data.status == 'created') {
		this.data.component.getActionButton('Save').setVisible( false );
		this.data.component.getActionButton('Cancel').setVisible( false );
		this.data.component.setDisabled( true );
	}
};
// Action handlers
PuiHelperFormActionsEvent.prototype.Save = function ( doneCallback ) {
	var data = this.data.component.serialize();
	data.uuid = this.data.component.data.uuid;
	data.active = this.data.component.data.connectedTo.data.active;

	this.data.component.getActionButton('Save').setBusy( true );
	var that = this;
	jQuery.post(this.data.component.domEl.attr('action'), data, function (json) {
		that.data.component.clearErrors();
		that.data.component.getActionButton('Save').setBusy( false );
		if(json.status == 1) {
			that.data.component.disableButtons(true);
			that.data.component.data.connectedTo.disableButtons(true);			
			
			that.data.component.clearErrors();
			
			// display modal message
			that.data.window = new PuiWindow({
				version: 2,
				//title: "Paziņojums MSG_2",
				buttons: [
					new PuiButton({
						id: 'pui-msg-ok',
						label: "Labi",
						cssClass: "bold pui-primary",
						events: {
							'click': function ( event ) {
								event.preventDefault();
								that.data.window.destroy();
							}
						}
					})
				],
				onDestroy: function (){
					that.data.component.disableButtons(false);
					that.data.component.data.connectedTo.disableButtons(false);
				}				
			});
			
			// create message
			if( that.data.component.data.connectedTo.data.active == false ) {
				if(data.privacy == 0)
					var messageText = '&nbsp;';
				else var messageText = 'Tas tagad ir redzams Tavā publiski pieejamo notikumu sarakstā (<a href="' + json.url + '" target="_blank">Saite uz sarakstu</a>)<br/><br/> Lai ierakstu padarītu pārlūkojamu <i>Pilseta24.lv</i> portālu publiskajā meklēšanā, aktivizē to <i>Pilseta24.lv Notikumi</i> kalendārā spiežot pogu “Aktivizēt”.';
			}
			
			that.data.message = new PuiMessage({
				type: 'success',
				title: 'Ieraksts veiksmīgi saglabāts',
				content: messageText
			});
			// show it
			that.data.window.setContent(that.data.message);
			
			if(!isFunction(doneCallback))
				that.data.window.setVisible( true );
			
			that._lock();
			jQuery('#pui-page-title').html('<a href="'+json.ev_url+'" target="_blank">'+data.title+'</a>');
			
			// set form status
			that.data.component.data.status = 'created';
			
			// done callback
			if(isFunction(doneCallback)) {
				doneCallback();
			}
		} else {
			
			that.data.component.setErrors(json.errors);
			// display modal message
			that.data.window = new PuiWindow({
				version: 2,
				//title: "Kļūdas paziņojums MSG_1",
				buttons: [
					new PuiButton({
						id: 'pui-msg-ok',
						label: "Labi",
						cssClass: "bold pui-primary",
						events: {
							'click': function ( event ) {
								event.preventDefault();
								that.data.window.destroy();
							}
						}
					})
				],
				onDestroy: function (){
					that.data.component.disableButtons(false);
					that.data.component.data.connectedTo.disableButtons(false);
				}				
			});
			
			if(that.data.component.data.connectedTo.data.active == true) {
			var msgText = "Lai saglabātu notikumu, kas ir aktīvs <i>Pilseta24.lv Notikumi</i> kalendārā, Tev jānorāda atbilstoši nepieciešamā informācija.";
			} else var msgText = "Norādi atbilstoši nepieciešamo informāciju.";
			// create message
			that.data.message = new PuiMessage({
				type: 'error',
				title: 'Notikums diemžēl netika saglabāts',
				content: msgText
			});
			that.data.component.disableButtons(true);
			that.data.component.data.connectedTo.disableButtons(true);			
			// show it
			that.data.window.setContent(that.data.message);
			that.data.window.setVisible( true );
		}
	});
};
PuiHelperFormActionsEvent.prototype.Cancel = function () {
	this.data.component.clearErrors();
	this.data.component.getActionButton('Cancel').setBusy( true );
	var that = this;
	jQuery.post('/calendar/events/revert', { uuid: this.data.component.data.uuid }, function ( json ) {
		that.data.component.getActionButton('Cancel').setBusy( false );
		if(json.status == 1) {
			that.data.component.populate(json.data);
			if(that.data.component.data.status == 'created')
				that._lock();
			
		} else {
			//console.log('bad response');
		}
	});
};
PuiHelperFormActionsEvent.prototype.Edit = function () {

	if(this.data.component.data.connectedTo.data.active == true){
		
		this.data.component.disableButtons(true);
		this.data.component.data.connectedTo.disableButtons(true);
		var that = this;
		this.data.window = new PuiWindow({
		version: 2,
		//title: "Kļūdas paziņojums MSG_7",
		buttons: [
			new PuiButton({
				id: 'pui-msg-ok',
				label: "Atcelt",
				cssClass: "bold",
				events: {
					'click': function ( event ) {
						event.preventDefault();
						that.data.window.destroy();
					}
				}
			}),
			new PuiButton({
				id: 'pui-msg-ok',
				label: "Rediģēt",
				cssClass: "bold pui-primary",
				events: {
					'click': function ( event ) {
						event.preventDefault();
						that._unlock();
						that.data.window.destroy();
					}
				}
			})
		],
		onDestroy : function (){
			that.data.component.disableButtons(false); 
			that.data.component.data.connectedTo.disableButtons(false);
		}
	});
	// create message
	this.data.message = new PuiMessage({
		type: 'alert',
		title: 'Vai tiešām vēlies rediģēt ierakstu?',
		content: 'Notikums ir aktīvs <i>Pilseta24.lv Notikumi</i> kalendārā.'
	});
	// show it
	this.data.window.setContent(that.data.message);
	this.data.window.setVisible( true );
	} else this._unlock();
};
PuiHelperFormActionsEvent.prototype.Delete = function () {

	this.data.component.disableButtons(true);
	this.data.component.data.connectedTo.disableButtons(true);	
	// display modal message
	var that = this;
	this.data.window = new PuiWindow({
		version: 2,
		//title: "Kļūdas paziņojums MSG_4",
		buttons: [
			new PuiButton({
				id: 'pui-msg-ok',
				label: "Atcelt",
				cssClass: "bold",
				events: {
					'click': function ( event ) {
						event.preventDefault();
						that.data.window.destroy();
					}
				}
			}),
			new PuiButton({
				id: 'pui-msg-ok',
				label: "Dzēst",
				cssClass: "bold pui-primary",
				events: {
					'click': function ( event ) {
						event.preventDefault();
						that._delete();
					}
				}
			})
		],
		onDestroy : function (){
			that.data.component.disableButtons(false); 
			that.data.component.data.connectedTo.disableButtons(false);
		}
	});
	
	var messageText = '&nbsp;';
	
	if(this.data.component.data.connectedTo.data.active == true){
		messageText = 'Notikums ir aktīvs <i>Pilseta24.lv Notikumi</i> kalendārā.';
	}
	
	// create message
	this.data.message = new PuiMessage({
		type: 'alert',
		title: 'Vai tiešām vēlies dzēst notikumu?',
		content: messageText
	});
	// show it
	this.data.window.setContent(that.data.message);
	this.data.window.setVisible( true );
};

PuiHelperFormActionsEvent.prototype._lock = function () {
	// disable form
	this.data.component.setDisabled( true );
	// switch buttons
	this.data.component.getActionButton('Save').setVisible( false );
	this.data.component.getActionButton('Cancel').setVisible( false );
	
	this.data.component.getActionButton('Edit').setVisible( true );
	this.data.component.getActionButton('Delete').setVisible( true );
};
PuiHelperFormActionsEvent.prototype._unlock = function () {
	// enable form
	this.data.component.setDisabled( false );
	// show buttons
	this.data.component.getActionButton('Edit').setVisible( false );
	//this.data.component.getActionButton('Delete').setVisible( false );
	
	this.data.component.getActionButton('Save').setVisible( true );
	this.data.component.getActionButton('Cancel').setVisible( true );
};
PuiHelperFormActionsEvent.prototype._delete = function () {
	var that = this;
	
	this.data.window.data.buttons[0].setBusy( true );
	jQuery.post('/calendar/events/delete', { uuid: this.data.component.data.uuid }, function (json) {
		that.data.window.data.buttons[0].setBusy( false );
		if(json.status == 1) {
			that.data.component.reset();
			that._unlock();
			
			that.data.component.data.status = 'creating';
			that.data.window.destroy();
			that.data.component.data.connectedTo.getHelper('FormActionsShare')._delete();
			that.data.component.getActionButton('Delete').setVisible( false );
			// set page title
			jQuery('#pui-page-title').html('Ievietot notikumu');
			that.data.component.data.uuid = json.uuid;
			that.data.component.data.connectedTo.domEl.attr('data-content-uuid', json.uuid);
			jQuery('#pui-location-portal').hide();
			if(jQuery('#publish_special_top').length != 0)
				jQuery('#publish_special_top').attr('checked', false);
		} else {
			
		}
	});
};

/*

	--- Component: PuiHelperFormActionsShare ---
	
	Options: 
		- component

*/
var PuiHelperFormActionsShare = function ( objOptions ) {
	var that = this;
	this.options = objOptions;
	this.data = {};
	
	PuiHelperFormActionsEvent.superclass.constructor.call( this, this.options, this.data );
};
// Extends: PuiHelperFormActionsAbstract
extend( PuiHelperFormActionsShare, PuiHelperFormActionsAbstract );
// Setup 
PuiHelperFormActionsShare.prototype._setup = function () {
	this.data.component.data.active = (this.data.component.domEl.attr('data-active') == 'yes') ? true : false;
	if(this.data.component.data.status == 'creating') {
		this.data.component.getActionButton('Edit').setVisible( false );
		this.data.component.getActionButton('Cancel').setVisible( false );
	} else if(this.data.component.data.status == 'created') {
		this.data.component.getActionButton('Save').setVisible( false );
		this.data.component.getActionButton('Cancel').setVisible( false );
		this.data.component.setDisabled( true );
		if(jQuery('#publish_special_top').length != 0) {
			jQuery('#publish_special_top').attr('disabled', true);
		}
	}
	
	if(this.data.component.data.active == true){
		this.data.component.getActionButton('Activate').setVisible( false );
	} else {
		this.data.component.getActionButton('Deactivate').setVisible( false );
	}
};
// Action handlers
PuiHelperFormActionsShare.prototype.Activate = function () {
	var that = this;
	that.data.component.clearErrors();
	var data = that.data.component.serialize();
	data.contentType = that.data.component.domEl.attr('data-content-type');
	data.contentUuid = that.data.component.domEl.attr('data-content-uuid');
	data.active = true;
	data = extendHash(data, this.data.component.data.connectedTo.serialize());
	this.data.component.data.connectedTo.clearErrors();
	
	if(jQuery('#publish_special_top').length != 0) {
		data.top = (jQuery('#publish_special_top').is(':checked')) ? 1 : 0;
	}
	
	that.data.component.getActionButton('Activate').setBusy( true );
	jQuery.post(that.data.component.domEl.attr('action'), data, function (json) {
		that.data.component.getActionButton('Activate').setBusy( false );
		if(json.status == 1){
			that.data.component.getActionButton('Activate').setVisible( false );
			that.data.component.getActionButton('Deactivate').setVisible( true );
			that.data.component.clearErrors();
			
			// display modal message
			that.data.window = new PuiWindow({
				version: 2,
				//title: "Paziņojums MSG_3",
				buttons: [
					new PuiButton({
						id: 'pui-msg-ok',
						label: "Labi",
						cssClass: "bold pui-primary",
						events: {
							'click': function ( event ) {
								event.preventDefault();
								that.data.window.destroy();
							}
						}
					})
				]
			});
			
			that.data.message = new PuiMessage({
				type: 'success',
				title: 'Notikums veiksmīgi aktivizēts! ',
				content: 'Tagad tas ir pārlūkojams <i>Pilseta24.lv</i> portālu publiskajā meklēšanā, jo Tu to aktivizēji <i>Pilseta24.lv Notikumi</i> kalendārā.'
			});
			// show it
			that.data.window.setContent(that.data.message);
			that.data.window.setVisible( true );
			
			// change status
			that.data.component.data.active = true;
			that.data.component.data.status = 'created';
			
			// lock form
			that._lock();
			that.data.component.data.connectedTo.getHelper('FormActionsEvent')._lock();
		} else {
			that.data.component.setErrors(json.errors);
			if(isDefined(json.event_errors) && json.event_errors != null) {
				that.data.component.data.connectedTo.getHelper('FormActionsEvent')._unlock();
				that.data.component.data.connectedTo.setErrors(json.event_errors);
			}
			
			// display modal message
			that.data.window = new PuiWindow({
				version: 2,
				//title: "Paziņojums MSG_10",
				buttons: [
					new PuiButton({
						id: 'pui-msg-ok',
						label: "Labi",
						cssClass: "bold pui-primary",
						events: {
							'click': function ( event ) {
								event.preventDefault();
								that.data.window.destroy();
							}
						}
					})
				],
				onDestroy: function (){
					that.data.component.disableButtons(false);
					that.data.component.data.connectedTo.disableButtons(false);
				}
			});
			// disable buttons
			that.data.component.disableButtons(true);
			that.data.component.data.connectedTo.disableButtons(true);			
			that.data.message = new PuiMessage({
				type: 'error',
				title: 'Notikums diemžēl netika aktivizēts.',
				content: 'Lai aktivizētu notikumu, <i>Pilseta24.lv Notikumi</i> kalendārā, Tev jānorāda atbilstoši nepieciešamā informācija.'
			});
			// show it
			that.data.window.setContent(that.data.message);
			that.data.window.setVisible( true );
		}
	});
};
PuiHelperFormActionsShare.prototype.Deactivate = function () {
	var that = this;
	this.data.component.disableButtons(true);
	this.data.component.data.connectedTo.disableButtons(true);	
	
	// display modal message
	this.data.window = new PuiWindow({
		version: 2,
		//title: "Paziņojums MSG_6",
		buttons: [
			new PuiButton({
				id: 'pui-msg-ok',
				label: "Atcelt",
				cssClass: "bold",
				events: {
					'click': function ( event ) {
						event.preventDefault();
						that.data.window.destroy();
					}
				}
			}),
			new PuiButton({
				id: 'pui-msg-ok',
				label: "Deaktivizēt",
				cssClass: "bold pui-primary",
				events: {
					'click': function ( event ) {
						event.preventDefault();
						that._deactivate();
					}
				}
			})
		],
		onDestroy : function (){
			that.data.component.disableButtons(false); 
			that.data.component.data.connectedTo.disableButtons(false);
		}
	});
	
	that.data.message = new PuiMessage({
		type: 'alert',
		title: 'Vai tiešām vēlies deaktivizēt notikumu?',
		content: 'Ja deaktivizēsi notikumu, tas vairs nebūs pārlūkojams <i>Pilseta24.lv</i> portālu publiskajā meklēšanā. <br/><br/>Pēc deaktivizēšanas tas joprojām būs pieejams Tavā publiski redzamo notikumu sarakstā.'
	});
	// show it
	that.data.window.setContent(that.data.message);
	that.data.window.setVisible( true );
};
PuiHelperFormActionsShare.prototype.Save = function () {
		var that = this;
		
		that.data.component.clearErrors();
		var data = that.data.component.serialize();
		data.contentType = that.data.component.domEl.attr('data-content-type');
		data.contentUuid = that.data.component.domEl.attr('data-content-uuid');
		
		data = extendHash(data, this.data.component.data.connectedTo.serialize());
		this.data.component.data.connectedTo.clearErrors();
		
		if(jQuery('#publish_special_top').length != 0) {
			data.top = (jQuery('#publish_special_top').is(':checked')) ? 1 : 0;
		}
		
		that.data.component.getActionButton('Save').setBusy( true );
		jQuery.post(that.data.component.domEl.attr('action'), data, function (json) {
			that.data.component.getActionButton('Save').setBusy( false );
			if(json.status == 1){
				that.data.component.clearErrors();
				
				// display modal message
				that.data.window = new PuiWindow({
					version: 2,
					//title: "Paziņojums MSG_5",
					buttons: [
						new PuiButton({
							id: 'pui-msg-ok',
							label: "Labi",
							cssClass: "bold pui-primary",
							events: {
								'click': function ( event ) {
									event.preventDefault();
									that.data.window.destroy();
								}
							}
						})
					]
				});
				
				if(that.data.component.data.active == true) {
					var msgText = "Publicēšanas iestatījumi veiksmīgi saglabāti.";
				}
				else var msgText = 'Notikums un tā publicēšanas iestatījumi ir veiksmīgi saglabāti.<br/><br/>Lai ierakstu padarītu pārlūkojamu <i>Pilseta24.lv</i> portālu publiskajā meklēšanā, aktivizē to <i>Pilseta24.lv Notikumi</i> kalendārā spiežot pogu “Aktivizēt”.';
				
				that.data.message = new PuiMessage({
					type: 'success',
					title: 'Notikums un publicēšanas iestatījumi saglabāti.',
					content: msgText
				});
				// show it
				that.data.window.setContent(that.data.message);
				that.data.window.setVisible( true );
				that.data.component.data.status = 'created';
				
				// lock form
				that._lock();
				that.data.component.data.connectedTo.getHelper('FormActionsEvent')._lock();
			} else {
				that.data.component.setErrors(json.errors);
				if(isDefined(json.event_errors) && json.event_errors != null) {
					that.data.component.data.connectedTo.getHelper('FormActionsEvent')._unlock();
					that.data.component.data.connectedTo.setErrors(json.event_errors);
				}
				// display modal message
				that.data.window = new PuiWindow({
					version: 2,
					//title: "Paziņojums MSG_9",
					buttons: [
						new PuiButton({
							id: 'pui-msg-ok',
							label: "Labi",
							cssClass: "bold pui-primary",
							events: {
								'click': function ( event ) {
									event.preventDefault();
									that.data.window.destroy();
								}
							}
						})
					],
					onDestroy: function (){
						that.data.component.disableButtons(false);
						that.data.component.data.connectedTo.disableButtons(false);
					}					
				});
				that.data.component.disableButtons(true);
				that.data.component.data.connectedTo.disableButtons(true);				
				that.data.message = new PuiMessage({
					type: 'error',
					title: 'Publicēšanas iestatījumi un notikums diemžēl netika saglabāti.',
					content: 'Lai saglabātu publicēšanas iestatījumus un notikumu, Tev jānorāda atbilstoši nepieciešamā informācija.'
				}); 
				// show it
				that.data.window.setContent(that.data.message);
				that.data.window.setVisible( true );
			}
	});
};
PuiHelperFormActionsShare.prototype.Edit = function () {
	if(this.data.component.data.active == true) {
		this.data.component.disableButtons(true); 
		this.data.component.data.connectedTo.disableButtons(true);		
		
		var that = this;
		// display modal message
		that.data.window = new PuiWindow({
			version: 2,
			//title: "Paziņojums MSG_11",
			buttons: [
				new PuiButton({
					id: 'pui-msg-ok',
					label: "Atcelt",
					cssClass: "bold",
					events: {
						'click': function ( event ) {
							event.preventDefault();
							that.data.window.destroy();
						}
					}
				}),
				new PuiButton({
					id: 'pui-msg-ok',
					label: "Rediģēt",
					cssClass: "bold pui-primary",
					events: {
						'click': function ( event ) {
							event.preventDefault();
							that._unlock();
							that.data.window.destroy();
						}
					}
				})
			],
			onDestroy : function (){
				that.data.component.disableButtons(false); 
				that.data.component.data.connectedTo.disableButtons(false);
			}
		});
		
		that.data.message = new PuiMessage({
			type: 'alert',
			title: 'Vai tiešām vēlies rediģēt publicēšanas iestatījumus?',
			content: '&nbsp;'
		});
		// show it
		that.data.window.setContent(that.data.message);
		that.data.window.setVisible( true );
	} else this._unlock();
};
PuiHelperFormActionsShare.prototype.Cancel = function () {
	this.data.component.clearErrors();
	this.data.component.getActionButton('Cancel').setBusy( true );
	var that = this;
	jQuery.post('/calendar/share/revert', { contentUuid: this.data.component.domEl.attr('data-content-uuid') }, function ( json ) {
		that.data.component.getActionButton('Cancel').setBusy( false );
		if(json.status == 1) {
			that.data.component.populate(json.data);
			that._lock();
		} else {
			//console.log('bad response');
		}
	});
};


PuiHelperFormActionsShare.prototype._lock = function () {
	this.data.component.setDisabled( true );
	
	this.data.component.getActionButton('Edit').setVisible( true );
	
	if(jQuery('#publish_special_top').length != 0) {
		jQuery('#publish_special_top').attr('disabled', true);
	}
	
	this.data.component.getActionButton('Save').setVisible( false );
	this.data.component.getActionButton('Cancel').setVisible( false );
};
PuiHelperFormActionsShare.prototype._unlock = function () {
	this.data.component.setDisabled( false );
	this.data.component.getActionButton('Edit').setVisible( false );
	
	if(jQuery('#publish_special_top').length != 0) {
		jQuery('#publish_special_top').attr('disabled', false);
	}
	
	this.data.component.getActionButton('Save').setVisible( true );
	this.data.component.getActionButton('Cancel').setVisible( true );
};
PuiHelperFormActionsShare.prototype._deactivate = function () {
	this.data.window.data.buttons[1].setBusy( true );
	
	var data = this.data.component.serialize();
	data.contentType = this.data.component.domEl.attr('data-content-type');
	data.contentUuid = this.data.component.domEl.attr('data-content-uuid');
	data.active = 0;
	
	data = extendHash(data, this.data.component.data.connectedTo.serialize());
	
	var that = this;
	jQuery.post(this.data.component.domEl.attr('action'), data, function (json) {
		if(json.status == 1){
			that.data.window.destroy();
			
			// switch buttons
			that.data.component.getActionButton('Activate').setVisible( true );
			that.data.component.getActionButton('Deactivate').setVisible( false );
			
			// set status
			that.data.component.data.active = false;
		} else {
			//console.log('bad response');
		}
	});
};
PuiHelperFormActionsShare.prototype._delete = function () {
	this.data.component.reset();
	this._unlock();
	
	// show activate button and hide deactivate
	this.data.component.getActionButton('Activate').setVisible( true );
	this.data.component.getActionButton('Deactivate').setVisible( false );
	this.data.component.getActionButton('Cancel').setVisible( false );
	jQuery('#pui-facet2').addClass('pui-hidden');
	
	// set active and status
	this.data.component.data.active = false;
	this.data.component.data.status = 'creating';
	
	//console.log('delete share');
};

/*

	--- Component: PuiHelperFormActionsComment ---
	
	Options: 
		- component

*/
var PuiHelperFormActionsComment = function ( objOptions ) {
	var that = this;
	this.options = objOptions;
	this.data = {};
	
	PuiHelperFormActionsComment.superclass.constructor.call( this, this.options, this.data );
};
// Extends: PuiHelperFormActionsAbstract
extend( PuiHelperFormActionsComment, PuiHelperFormActionsAbstract );
// Setup 
PuiHelperFormActionsComment.prototype._setup = function () {
	// setup switch to anonymous
	var that = this;
	this.attachEvents(jQuery('#anonymous'), {
		'click': that.onAnonymousHandler
	});
};

PuiHelperFormActionsComment.prototype.Save = function () {
	this.data.component.clearErrors();
	var that = this;
	this.data.component.getActionButton('Save').setBusy( true );
	var data = this.data.component.serialize();
	
	if(jQuery('#anonymous').is(':checked'))
		data.anonymous = 1;
	else data.anonymous = 0;
	
	jQuery.post(this.data.component.domEl.attr('action'), data, function(json){
		that.data.component.getActionButton('Save').setBusy( false );
	    if(json.status == 1){
	        var li = jQuery('<li class="pui-active"></li>');
	        li.html(['<p class="pui-item-creator">', json.comment.profile, '</p><p class="pui-item-description">', json.comment.text, '</p>'].join(''));
	        li.prependTo(jQuery('#pui-comments-list'));
	        
	        that.data.component.getInput('text').setValue('');
			that.data.component.getInput('username').setValue('');
			jQuery('#anonymous').attr('checked', false);
			jQuery('#pui-comment-actions').hide();
			jQuery('#pui-comment-user-profile').find('a').show();
			jQuery('#pui-comment-user-profile').find('input').hide();
	    } else {
	    	that.data.component.setErrors(json.errors);
	    }
	});
};
PuiHelperFormActionsComment.prototype.Cancel = function () {
	this.data.component.clearErrors();
	this.data.component.getInput('text').setValue('');
	this.data.component.getInput('username').setValue('');
	jQuery('#anonymous').attr('checked', false);
	jQuery('#pui-comment-actions').hide();
	jQuery('#pui-comment-user-profile').find('a').show();
	jQuery('#pui-comment-user-profile').find('input').hide();
};
PuiHelperFormActionsComment.prototype.onAnonymousHandler = function (event) {
	if(jQuery(event.currentTarget).is(':checked')) {
		jQuery('#pui-comment-user-profile').find('a').hide();
		jQuery('#pui-comment-user-profile').find('input').show().focus();
	} else {
		jQuery('#pui-comment-user-profile').find('a').show();
		jQuery('#pui-comment-user-profile').find('input').hide();
	}
};

/*

	--- Component: PuiHelperFormActionsShare ---
	
	Obj Options: 
		venueid = int				- venue id, Edit modee izmanto
		latlng = {lat:x, lng:y} 	- preset map with specified coordinates
		locid = int					- preset with specified location id. Async field values set.
		callback = function(json){}	- callback function. Executed after successful save
*/
var PuiHelperSuggestVenue = function ( objOptions ) {
	var that = this;
	this.options = objOptions;
	this.data = {
		venueOrLocation: (isDefined(this.options.venueOrLocation)) ? this.options.venueOrLocation : false
	};
	
	PuiHelperSuggestVenue.superclass.constructor.call( this, this.options, this.data );
	// ja ir preset map point
	this.latlong = (isDefined(objOptions.latlng))?new google.maps.LatLng(objOptions.latlng.lat, objOptions.latlng.lng):null;
	this.locid = (isDefined(objOptions.locid))?objOptions.locid:null;
	this.venueid = (isDefined(objOptions.venueid))?objOptions.venueid:null;
	this.callback = (isDefined(objOptions.callback) && isFunction(objOptions.callback))?objOptions.callback:null;
	
	this._setup();
};
// Extends: PuiHelperFormActionsAbstract
extend( PuiHelperSuggestVenue, PuiComponentAbstract );
// setup
PuiHelperSuggestVenue.prototype._setup = function () {
	var that = this;
	this.data.window = new PuiWindow({
		title: that.options.title,
		version: 2,
		buttons: [
			new PuiButton({
				id: 'pui-msg-ok',
				label: "Atcelt",
				cssClass: "bold",
				events: {
					'click': function (event){
						event.preventDefault();
						that.data.window.destroy();
					}
				}
			}),
			new PuiButton({
				id: 'pui-msg-ok',
				label: "Apstiprināt",
				cssClass: "bold pui-primary"
			})
		]
	});
	
	var params = isDefined(this.options.params)?this.options.params:false;
	
	this.data.window.setContent({
		
		url: '/calendar/venues/suggest', 
		params: params,
		callback: function (html){
			var suggestForm = new PuiForm({
				id: 'venue_suggest'
			});
			
			if (null != that.venueid){
				
			}
			
			// title
			suggestForm.addInput(new PuiInputText({
				id: 'venue_title'
			}), 'title');
			// type
			suggestForm.addInput(new PuiInputSelect({
				id: 'venue_type'
			}), 'type');
			// location
			suggestForm.addInput(new PuiInputText({
				id: 'venue_location'
			}), 'location');

			// Caur shito tiek pievienots PuiHelperAutocompleteInput. @see #910
			suggestForm.getInput('location').attachHelpers({
				'AutocompleteInput': {
					url: '/calendar/venues/locations',
					// venue custom params
					params: {exclude: 7},
					callback: function (row) {
						$('#pui-venue-map').show();
	                    $('#pui-venue-address').show();
	                    google.maps.event.trigger(suggestForm.getInput('coordinates').map.map, 'resize');
	                    suggestForm.getInput('coordinates').positionMapByLocationName(row);	                    
					}
				},
				'DescriptionInner': {
					text: "Sāc rakstīt pilsētas, pilsētas daļas, novada, pagasta vai ciema nosaukumu"
				}
			});
			// address
			suggestForm.addInput(new PuiInputText({
				id: 'venue_address'
			}), 'address');
			
			var coord = new PuiInputCoordinates({
                input: $('#pui-dot-on-map'),
                inputForAddress: $('#venue_address'),
                inputForLat: $('#venue_latitude'),
                inputForLong: $('#venue_longitude')
			});
			
			suggestForm.addInput(coord, 'coordinates');

			// preset map location
			if (null != that.latlong){
				coord.positionMap(that.latlong);
	          	google.maps.event.trigger(coord.map.map, 'resize');				
			}
			
			// preset with location
			if (null != that.locid){
				// PuiHelperAutocompleteInput
				var h = suggestForm.getInput('location').getHelper('AutocompleteInput');
				$.get('/calendar/venues/get-location/', {lid:that.locid}, function(d){
					if (d.status == 1)
						h.createPick(d.data);
				},'json');				
			}

			
			
			 that.attachEvents( that.data.window.data.buttons[1].domEl, {
			 	'click': function (event) {
			 		event.preventDefault();
				
					suggestForm.clearErrors();
			 		jQuery.post(suggestForm.domEl.attr('action'), $('#venue_suggest').serialize(), function (json) {

			 			if(json.status == 1) {
//			 				if (false != that.data.venueOrLocation)
//			 					that.data.venueOrLocation.setValue({venue: json.data});
							that.data.window.destroy();
							
				 			if (null != that.callback)
				 				that.callback(json.data);
			 			} else {
			 				suggestForm.setErrors(json.errors);
			 			}
			 		});
			 	}
			 } );
		}
	});
	this.data.window.setVisible( true );
};

// Helper functions
function _showLoginForm() {
	if(!isFunction(PuiCache.getNamespace('login_form').get('window').setVisible) || PuiCache.getNamespace('login_form').get('window').data.deleted)
		var _window = new PuiWindow({
			title: "Ielogoties",
			version: 2
		});
	else var _window = PuiCache.getNamespace('login_form').get('window');
	
	
	_window.setContent({
		url: '/konts/ielogoties',
		callback: function () {
			jQuery('#email').focus();
			jQuery('#return_after_login').val(window.location.href);
		}
	});
	
	
	_window.setVisible( true );
	PuiCache.getNamespace('login_form').set('window', _window);
	return _window;
}

function _showModal(namespace, title, href, focus) {
	if(!isFunction(PuiCache.getNamespace(namespace).get('window').setVisible) || PuiCache.getNamespace(namespace).get('window').data.deleted)
		var _window = new PuiWindow({
			title: title,
			version: 2
		});
	else var _window = PuiCache.getNamespace(namespace).get('window');
	
	_window.setContent({
		url: href,
		callback: function () {
			jQuery('#'+focus).focus();
			jQuery('#return_after_login').val(window.location.href);
		}
	});
	
	_window.setVisible( true );
	PuiCache.getNamespace(namespace).set('window', _window);
	return _window;
}

function _openLinkInModal( element ) {
	element = jQuery( element );
	//console.log(element);
	if(!isFunction(PuiCache.getNamespace('link_in_modal').get('window').setVisible) || PuiCache.getNamespace('link_in_modal').get('window').data.deleted)
		var _window = new PuiWindow({
			title: element.attr('title'),
			version: 2,
			buttons: [
				new PuiButton({
					label: 'Labi',
					cssClass: 'bold pui-primary',
					events: {
						'click': function ( event ) {
							event.preventDefault();
							_window.destroy();
						}
					}
				})
			]
		});
	else var _window = PuiCache.getNamespace('link_in_modal').get('window');
	
	_window.setContent({
		url: element.attr('href')
	});
	_window.setVisible( true );
	PuiCache.getNamespace('link_in_modal').set('window', _window);
}
function _generateFacetUrl(strFacet, hashData) {
		
	
	var url = '';
	
	var _url = window.location.href.rtrim('/').split('/');
	var _vieta_index = -1;
	var _laiks_index = -1;
	
	// remove domain
	_url.shift();
	_url.shift();
	_url.shift();
	
	if(_url.length == 1) {
		_url.push('events');
	}
	
	// check page
	if(_url.length == 2) {
		_url.push('1');
	}
	
	// check if there is facets already
	jQuery.each(_url, function (index, element) {
		if(element.indexOf('vieta') > -1)
			_vieta_index = index;
		if(element.indexOf('laiks') > -1)
			_laiks_index = index;
	});
	
	if(strFacet == 'vieta') {
		if(_vieta_index > -1) {
			_url[_vieta_index] = ['vieta', hashData.location].join(':');
		} else _url.push(['vieta', hashData.location].join(':'));
	}
	
	// laiks
	if(strFacet == 'laiks') {
		if(isDefined(hashData.dateTo)) {
			var _date_url = [hashData.dateFrom.toCustomString(),  hashData.dateTo.toCustomString()].join('-');
		} else var _date_url = hashData.dateFrom.toCustomString();
		
		if (isDefined(hashData.browseMode) && hashData.browseMode === false){ // start mode
			_url = ['calendar','events', '1',   ['laiks', _date_url].join(':')];
			// vietas facets. Shis izpildaas no start modes, ja ir vietas facets 
			if(isDefined(hashData.addVietaFacet) && hashData.addVietaFacet !== false)
				_url.push(['vieta', hashData.addVietaFacet].join(':'));
		}
		else{
			if(_laiks_index > -1) {
				_url[_laiks_index] = ['laiks', _date_url].join(':');
			} else {
				_url.push(['laiks', _date_url].join(':'));
			}			
		}		
	}
	
	url = _url.join('/');
	
	return ['/', url].join('');
}
/** 
Peec shaadas url scheme:
/calendar/events/my/daily-statistics/laiks/13.10.2011
Ja jau shaads variable existee, tad tiek overwrite
**/
function _generateUrl(key, value){

	var _url = window.location.href.rtrim('/').split('/');
	var _vieta_index = -1;
	var _laiks_index = -1;

	// remove domain
	_url.shift();
	_url.shift();
	_url.shift();

	var variableExists = false;
	var varIndex = 0;
	
	// check vai taads jau nav
	jQuery.each(_url, function (i, element) {
		if (element.indexOf(key) == 0){
			// key ir. chekojam vai ir value.
			if (_url.length > ++i){
				varIndex = i;
				variableExists = true;
			}
			return false; // break
		}
	});

	if (variableExists)
		_url[varIndex] = value;
	else
		_url.push(key, value);

	_url = '/'+_url.join('/');
	
	return _url;		
}


var SocialNetwork = function (){
	this._mailWindow = null;
	this._init();
};

SocialNetwork.prototype._init = function(){
	
}

SocialNetwork.prototype.showMailModal = function(){
	var that = this;
	if (null == this._mailWindow){
		this._mailWindow = new PuiWindow({
			version: 2,
			title: 'E-mail required',
			buttons: [
				new PuiButton({
					id: 'pui-email-cancel',
					label: "Atcelt",
					cssClass:"bold",
					events: {
						'click': function (event){
							event.preventDefault();
							that._mailWindow.destroy();
						}
					}
				}),
				new PuiButton({
					id: 'pui-email-ok',
					label: "Apstiprināt",
					cssClass:"bold pui-primary",
					events: {
						'click': function (event){
							
							event.preventDefault();
							var lauks = jQuery('#email-g'); 
							if (lauks.val() == ''){
								lauks.addClass('pui-error');
								lauks.focus();
							}
							else{
								that._mailWindow.data.buttons[1].setBusy( true );
								jQuery.post('/konts/confirm-netw-account', jQuery('#network-email').serialize(), function(json){
									if(json.status == 1) {
										that._mailWindow.destroy();
										// raadam successful msg
										var _succWindow = new PuiWindow({
											version: 2,
											title: 'Cool',
											buttons: [
												new PuiButton({
													id: 'pui-succ-ok',
													label: "Close",
													cssClass:"bold pui-primary",
													events: {
														'click': function (event){
															event.preventDefault();
															//_message.destroy();
															_succWindow.destroy();
														}
													}
												})
											],
											onDestroy : function (){_succWindow = null;}
										});
										var _message = new PuiMessage({
											type: 'alert',
											title: "Mail sent",
											content: "Check your mailbox"
										});
										
										_succWindow.setContent(_message);										
										_succWindow.setVisible( true );
									}
									else{
										that._mailWindow.data.buttons[1].setBusy(false);
										alert('Kļūda. Please try again.');
									}
								}, 'json');
							}
						}
					}
				})
			],
			onDestroy : function (){that._mailWindow = null;}
		});		
	}
	this._mailWindow.setContent({url: "/konts/render-email-form"});
	this._mailWindow.setVisible(true);
	
}


