// Alg. Funktionen
function getTickCount () {
 var T = new Date();
 return T.getMilliseconds() + T.getSeconds() * 1000 + T.getMinutes() * 60000 + T.getHours() * 3600000 + T.getDay() * 86400000;
}

function clone (obj, runConstructors, chain) { // Abgeaendert von http://forum.de.selfhtml.org/archiv/2009/3/t185276/
 if (obj == null || typeof(obj) != 'object') return obj;
 if (!chain) chain = new Array(obj);
 else {
  for (var i = 0; i < chain.length; i++) if (chain[i] == obj) return obj;
  chain.push(obj);
 }
 if (runConstructors) var c = new obj.constructor(); else var c = new Object();
 for (var key in obj) if (typeof(obj) == 'object') c[key] = clone(obj[key], runConstructors, chain); else c[key] = obj[key];
 return c;
}

function JSWEffect_terminate (win, _break) {
 if (!win.effect) return;
 if (win.effect['interval']) window.clearInterval(win.effect['interval']);
 win.effect['interval'] = null;
 win.effect['stop'] = Number.NaN;
 var b = false;
 if (!_break) b = win.effect['fkt'](win);
 win.effect = null;
 return b;
}





// Effekte
function JSWEffect_Blend (win, duration, onTerminate, opacity) {
 if (duration) { // start
  if (!window.getComputedStyle) return; // Keinen Effekt fuer alten IE
  var style = window.getComputedStyle(win.el['OuterBox']);
  
  if (JSWEffect_terminate(win, (win.effect && win.effect['fkt'] == JSWEffect_Blend && !win.effect.onTerminate)?true:false)) return; // Falls aktiv, laufenden Effekt beenden; falls laufender Effekt JSWEffect_Blend ist, nur abbrechen
  win.effect = new Object();
  win.effect['fkt'] = JSWEffect_Blend;
  win.effect['onTerminate'] = onTerminate;
  win.effect['start'] = getTickCount();
  win.effect['stop'] = win.effect['start'] + duration;
  if (style && style['visibility'] == 'visible') win.effect['startOP'] = parseFloat(style['opacity']);
  else {
   win.effect['startOP'] = 0;
   win.el['OuterBox'].style.opacity = 0;
   win.el['OuterBox'].style.visibility = 'visible';
  }
  win.effect['stopOP'] = opacity;
  win.effect['interval'] = window.setInterval(JSWEffect_Blend, 20, win);
 }
 var t = getTickCount();
 if (isNaN(win.effect['stop']) || t >= win.effect['stop']) { // stop
  if (win.effect['interval']) window.clearInterval(win.effect['interval']);
  win.effect['interval'] = null;
  win.el['OuterBox'].style.opacity = win.effect['stopOP'];
  var onTerm = win.effect['onTerminate'];
  win.effect = null;
  if (onTerm) return onTerm(win);
 } else { // effect
  var s = (t - win.effect['start']) / (win.effect['stop'] - win.effect['start']);
  win.el['OuterBox'].style.opacity = s * win.effect['stopOP'] + (1-s) * win.effect['startOP'];
 }
}

function JSWEffect_ThrowBorder (win, duration, onTerminate, top, left, width, height, reverse) {
 if (duration) { // start
  if (JSWEffect_terminate(win)) return; // Falls aktiv, laufenden Effekt beenden
  win.effect = new Object();
  win.effect['fkt'] = JSWEffect_ThrowBorder;
  win.effect['start'] = getTickCount();
  win.effect['stop'] = win.effect['start'] + duration;
  win.effect['onTerminate'] = onTerminate;
  var p = win.getWindowPos();
  win.effect['startTop'] = (reverse)?top:p[1];
  win.effect['startLeft'] = (reverse)?left:p[0];
  win.effect['startWidth'] = (reverse)?width:win.el['OuterBox'].offsetWidth;
  win.effect['startHeight'] = (reverse)?height:win.el['OuterBox'].offsetHeight;
  win.effect['stopTop'] = (reverse)?p[1]:top;
  win.effect['stopLeft'] = (reverse)?p[0]:left;
  win.effect['stopWidth'] = (reverse)?win.el['OuterBox'].offsetWidth:width;
  win.effect['stopHeight'] = (reverse)?win.el['OuterBox'].offsetHeight:height;
  win.effect['border'] = document.createElement('div');
  win.effect['border'].className = 'JSW ThrowingBorder';
  document.body.appendChild(win.effect['border']);
  win.effect['border'].style.top = win.effect['startTop'] + 'px';
  win.effect['border'].style.left = win.effect['startLeft'] + 'px';
  win.effect['border'].style.width = win.effect['startWidth'] + 'px';
  win.effect['border'].style.height = win.effect['startHeight'] + 'px';
  if (win.mgr) win.effect['border'].style.zIndex = win.mgr.maxZ + 1;
  win.effect['interval'] = window.setInterval(JSWEffect_ThrowBorder, 20, win);
 }
 var t = getTickCount();
 if (isNaN(win.effect['stop']) || t >= win.effect['stop']) { // stop
  if (win.effect['interval']) window.clearInterval(win.effect['interval']);
  win.effect['interval'] = null;
  document.body.removeChild(win.effect['border']);
  win.effect['border'] = null;
  win.setOffsetPosition(win.effect['stopTop'], win.effect['stopLeft'], win.effect['stopWidth'], win.effect['stopHeight']);
  var onTerm = win.effect['onTerminate'];
  win.effect = null;
  if (onTerm) return onTerm(win);
 } else { // effect
  var s = (t - win.effect['start']) / (win.effect['stop'] - win.effect['start']);
  win.effect['border'].style.top = s * win.effect['stopTop'] + (1-s) * win.effect['startTop'] + 'px';
  win.effect['border'].style.left = s * win.effect['stopLeft'] + (1-s) * win.effect['startLeft'] + 'px';
  win.effect['border'].style.width = s * win.effect['stopWidth'] + (1-s) * win.effect['startWidth'] + 'px';
  win.effect['border'].style.height = s * win.effect['stopHeight'] + (1-s) * win.effect['startHeight'] + 'px';
 }
}





// JSWindow
function JSWindow (_el) {
 // Objekte/Arrays initialisieren
 this.eventListeners = new Array();
 this.selfEventListeners = new Object();
 this.parentElement = (_el)?_el.parentElement:null;
 this.appended = (this.parentElement)?true:false;
 this.el = new Object();
 this.el['OuterBox'] = _el;
 this.visible = this.appended;
 this.pos = new Object();
 this.pos['position'] = 'absolute';
 // Alle Elemente verlinken/erstellen
 var search = true; // falls (spaeter) auf falls gesetzt, so spart sich autoCreateEl die Suche und erstellt das ELement sofort.
 var _this = this;
 function autoCreateEl(tag, className, parentEl) { // versucht, ein Element vom typ tag und mit entsprechendem className in parentEl zu finden. Wenn nicht vorhanden, wird ein entsprechendes Element erstellt.
  if (search) for (var i = 0; i < parentEl.childNodes.length; i++) {
   if (parentEl.childNodes[i].nodeType != 1) continue;
   if (parentEl.childNodes[i].nodeName.toLowerCase() != tag) continue;
   var _className = ' '+parentEl.childNodes[i].className+' ';
   if (_className.indexOf(' '+className+' ') < 0) continue;
   if (_className.indexOf(' JSW ') < 0) continue;
   _this.el[className] = parentEl.childNodes[i];
   return;
  }
  _this.el[className] = document.createElement(tag);
  _this.el[className].className = 'JSW ' + className;
  if (parentEl) parentEl.appendChild(_this.el[className]);
 }
 if (!this.el['OuterBox']) {
  search = false;
  this.el['OuterBox'] = document.createElement('div');
  this.el['OuterBox'].className = 'JSW OuterBox';
 }
 this.el['OuterBox'].jswLinkedWindow = this;
 autoCreateEl('div', 'InnerBox', this.el['OuterBox']);
 autoCreateEl('div', 'BorderTop', this.el['OuterBox']);
 autoCreateEl('div', 'BorderLeft', this.el['OuterBox']);
 autoCreateEl('div', 'BorderRight', this.el['OuterBox']);
 autoCreateEl('div', 'BorderBottom', this.el['OuterBox']);
 autoCreateEl('div', 'EdgeTopLeft', this.el['OuterBox']);
 autoCreateEl('div', 'EdgeTopRight', this.el['OuterBox']);
 autoCreateEl('div', 'EdgeBottomLeft', this.el['OuterBox']);
 autoCreateEl('div', 'EdgeBottomRight', this.el['OuterBox']);
 autoCreateEl('div', 'Bar', this.el['OuterBox']);
 autoCreateEl('span', 'Title', this.el['Bar']);
 autoCreateEl('div', 'Buttons', this.el['Bar']);
 autoCreateEl('a', 'ButtonExclude', this.el['Buttons']); this.el['ButtonExclude'].href = 'javascript: \/* '+this.lang.get('newWin')+' *\/';
 autoCreateEl('a', 'ButtonMinimize', this.el['Buttons']); this.el['ButtonMinimize'].href = 'javascript: \/* '+this.lang.get('minimize')+' *\/';
 autoCreateEl('a', 'ButtonMaximize', this.el['Buttons']); this.el['ButtonMaximize'].href = 'javascript: \/* '+this.lang.get('maximize')+' *\/';
 autoCreateEl('a', 'ButtonClose', this.el['Buttons']); this.el['ButtonClose'].href = 'javascript: \/* '+this.lang.get('close')+' *\/';
 // Kontextmenue
 this.el['Bar'].contextmenu = new Array(
  {'text':this.lang.get('newWin'),   'obj':this, 'fkt':this.exclude, 'isenabled':function(){return _this.excludable;}},
  {'text':this.lang.get('minimize'), 'obj':this, 'fkt':this.minimize, 'isenabled':function(){return _this.minimizable;}},
  {'text':this.lang.get('maximize'), 'obj':this, 'fkt':this.maximize, 'isenabled':function(){return _this.maximizable;}},
  {'text':this.lang.get('close'),    'obj':this, 'fkt':this.hide, 'isenabled':function(){return _this.closable;}}
 );
 // Positionsstyle feststellen
 if (_el) {
  this.offsetParent = this.el['OuterBox'].offsetParent;
  var style = (window.getComputedStyle)?window.getComputedStyle(this.el['OuterBox'], null):this.el['OuterBox'].currentStyle;
  if (!style) throw 'Existing Element is not completely initialized. This can be the case, if the element is not inserted into the document or sometimes if the site is in an iframe.';
  var realStyle = new Object();
  var s = this.el['OuterBox'].getAttribute('style', false).replace(/\s/g, '').toLowerCase().split(';');
  for (var i = 0; i < s.length; i++) { s[i] = s[i].split(':'); if (!s[i][0]) continue; realStyle[s[i][0]] = s[i][1]; }
  var posNumX = 0;
  var posNumY = 0;
  this.pos['position'] = style.position;
  function positionToInt (p, x) {
   if (realStyle[p] && realStyle[p] != 'auto') {
    if (x) posNumX++; else posNumY++;
    _this.pos[p] = parseInt(style[p]);
    if (realStyle[p].indexOf('%') > 0) _this.pos[p+'Percent'] = true;
    else _this.pos[p+'Percent'] = false;
   } else {
    _this.pos[p] = Number.NaN;
    _this.pos[p+'Percent'] = false;
   }
  }
  positionToInt('top', false);
  positionToInt('left', true);
  positionToInt('right', true);
  positionToInt('bottom', false);
  positionToInt('width', true);
  positionToInt('height', false);
  if (posNumX == 0) { posNumX++; this.pos['left'] = this.el['OuterBox'].offsetLeft; }
  if (posNumY == 0) { posNumY++; this.pos['top'] = this.el['OuterBox'].offsetTop; }
  if (posNumX == 1) { if (isNaN(this.pos['width'])) this.pos['width'] = this.el['OuterBox'].offsetWidth; else this.pos['left'] = this.el['OuterBox'].offsetLeft; }
  if (posNumY == 1) { if (isNaN(this.pos['height'])) this.pos['height'] = this.el['OuterBox'].offsetHeight; else this.pos['top'] = this.el['OuterBox'].offsetTop; }
  if (posNumX == 3) this.pos['right'] = Number.NaN;
  if (posNumY == 3) this.pos['bottom'] = Number.NaN;
 } else {
  this.pos.top = 0;
  this.pos.left = 0;
  this.pos.width = this.minWidth;
  this.pos.height = this.minHeight;
 }
 // Event-Listener setzen
 this.onEvent(this.el['OuterBox'], 'mousedown', this.mouseDown);
 this.onEvent(document, 'resize', this.documentResize);
 this.onEvent(this.el['ButtonExclude'], 'click', function () { this.exclude(true); });
 this.onEvent(this.el['ButtonMinimize'], 'click', this.minimize);
 this.onEvent(this.el['ButtonMaximize'], 'click', function () { if (this.maximized) this.normalize(); else this.maximize(); });
 this.onEvent(this.el['ButtonClose'], 'click', this.hide);
 // setter aufrufen
 var s = ' '+this.el['Buttons'].className+' ';
 if (s.indexOf(' nonmaximizable ') >= 0) this.maximizable = false;
 if (s.indexOf(' nonminimizable ') >= 0) this.minimizable = false;
 if (s.indexOf(' nonclosable ') >= 0) this.closable = false;
 if (s.indexOf(' nonexcludable ') >= 0) this.excludable = false;
 s = ' '+this.el['OuterBox'].className+' ';
 if (s.indexOf(' nonresizable ') >= 0) this.resizable = false;
 if (s.indexOf(' nonmovable ') >= 0) this.movable = false;
 if (s.indexOf(' autoheight ') >= 0) this.autoHeight = true;
 if (s.indexOf(' autowidth ') >= 0) this.autoWidth = true;
 if (this.el['Title'].innerHTML != '') this.title = this.el['Title'].innerHTML;
 for (var i = 0; i < this.el['Bar'].getElementsByTagName('img'); i++) {
  var ic = this.el['Bar'].getElementsByTagName('img')[i];
  if ((' '+ic.className+' ').indexOf('Icon') >= 0) {
   this.el['Bar'].removeChild(ic);
   this.icon = ic.src;
  }
 }
 // sonstiges
 if (this.hasAtr(this.el['OuterBox'], 'maximized')) this.maximize();
 this.setOrRmAtr(this.el['Buttons'], 'nonexcludable', !this._excludable);
 if (_el) this.freeOnHide = false;
}

JSWindow.prototype = {
 lang : {
  de : { minimize:'Minimieren', maximize:'Maximieren', close:'Schliessen', newWin:'In neuem Fenster oeffnen' },
  en : { minimize:'minimize', maximize:'maximize', close:'close', newWin:'open in new window' },
  get : function (key) {
   if (!this.l) {
    this.l = navigator.language;
    if (!this[this.l]) this.l = 'en';
   }
   return (this[this.l][key])?this[this.l][key]:key;
  }
 },

 // private
 eventListeners     : null, // EventListener, die von diesem Objekt gesetzt wurden
 selfEventListeners : null, // EventListener, die auf dieses Objekt gesetzt wurden
 disabledCount      : 0,
 // public readonly (darf von public gelesen werden, aber nur von ausgewaehlten Scripts geschrieben)
 parentElement : null,
 appended      : false,
 el            : null,
 visible       : false,
 pos           : null,
 effect        : null,
 maximized     : false,
 minimized     : false,
 excluded      : false,
 freed         : false,
 // public
 _resizable     : true, get resizable () { return this._resizable; }, set resizable (v) { this._resizable = v; this.setOrRmAtr(this.el['OuterBox'], 'nonresizable', !v); },
 _movable       : true, get movable () { return this._movable; }, set movable (v) { this._movable = v; this.setOrRmAtr(this.el['OuterBox'], 'nonmovable', !v); },
 effects        : null,
 mainFrame      : null,
 minWidth       : 40,
 minHeight      : 25,
 freeOnHide     : true,
 _maximizable   : true, get maximizable () { return this._maximizable; }, set maximizable (v) { this._maximizable = v; this.setOrRmAtr(this.el['Buttons'], 'nonmaximizable', !v); },
 _minimizable   : true, get minimizable () { return this._minimizable; }, set minimizable (v) { this._minimizable = v; this.setOrRmAtr(this.el['Buttons'], 'nonminimizable', !v); },
 _closable      : true, get closable () { return this._closable; }, set closable (v) { this._closable = v; this.setOrRmAtr(this.el['Buttons'], 'nonclosable', !v); },
 _excludable    : false, get excludable () { return this._excludable; }, set excludable (v) { this._excludable = v; this.setOrRmAtr(this.el['Buttons'], 'nonexcludable', !v); },
 minimizePoint  : function () { return new Array(0, 0); },
 minimalVisible : new Array(0, -10, -10, -10),
 _title         : '', get title () { return this._title; }, set title (v) { this.setTitle(v); },
 _icon          : '', get icon () { return this._icon; }, set icon (v) { this.setIcon(v); },
 _autoHeight : false, get autoHeight () { return this._autoHeight; }, set autoHeight (v) {
  if (this.freed) throw 'Object is freed';
  if (v == this._autoHeight) return;
  this._autoHeight = v;
  this.setOrRmAtr(this.el['OuterBox'], 'autoheight', v);
  if (this.mainFrame && this.mainFrame.communicator) this.mainFrame.communicator.autoHeight = v;
  if (v) {
   if (isNaN(this.pos.height)) this.el['OuterBox'].style.bottom = 'auto'; else this.el['OuterBox'].style.height = 'auto';
  } else {
   this.actualizePos();
   this.setPos();
   if (this.mainFrame) this.mainFrame.style.height = '100%';
  }
 },
 _autoWidth : false, get autoWidth () { return this._autoWidth; }, set autoWidth (v) {
  if (this.freed) throw 'Object is freed';
  if (v == this._autoWidth) return;
  this._autoWidth = v;
  this.setOrRmAtr(this.el['OuterBox'], 'autowidth', v);
  if (this.mainFrame && this.mainFrame.communicator) this.mainFrame.communicator.autoWidth = v;
  if (v) {
   if (isNaN(this.pos.width)) this.el['OuterBox'].style.right = 'auto'; else this.el['OuterBox'].style.width = 'auto';
  } else {
   this.actualizePos();
   this.setPos();
   if (this.mainFrame) this.mainFrame.style.width = '100%';
  }
 },
 
 extendBar : /* public */ function () {
  if (this.el.BarExtension) return this.el.BarExtension;
  this.el.BarExtension = document.createElement('div');
  this.el.BarExtension.className = 'JSW BarExtension';
  function onResize () {
   this.el.BarExtension.style.height = this.el.BarExtension.scrollHeight + 'px';
   this.el.OuterBox.style.paddingTop = (this.el.BorderTop.offsetHeight + this.el.Bar.offsetHeight + this.el.BarExtension.offsetHeight) + 'px';
  }
  this.onEvent(this.el.BarExtension, 'overflow', onResize);
  this.onEvent(this.el.BarExtension, 'underflow', onResize);
  this.el.OuterBox.appendChild(this.el.BarExtension);
  return this.el.BarExtension;
 },

 setIcon : /* protected */ function (v) { // to be overridden
  if (v == '' && this.el['Icon']) {
   this.el['Bar'].removeChild(this.el['Icon']);
   delete this.el['Icon'];
  }
  if (v != '' && !this.el['Icon']) {
   this.el['Icon'] = document.createElement('img');
   this.el['Icon'].className = 'JSW Icon';
   this.el['Bar'].insertBefore(this.el['Icon'], this.el['Title']);
  }
  this._icon = v;
  if (v != '') this.el['Icon'].src = v;
 },

 setTitle : /* protected */ function (v) { // to be overridden
  if (this.freed) throw 'Object is freed';
  this.el['Title'].innerHTML = v;
  this._title = v;
 },

 addEventListener : /* public */ function (type, fkt) {
  if (this.freed) throw 'Object is freed';
  if (!this.selfEventListeners[type]) this.selfEventListeners[type] = new Array();
  this.selfEventListeners[type].push(fkt);
 },

 removeEventListener : /* public */ function (type, fkt) {
  if (this.freed) throw 'Object is freed';
  if (!this.selfEventListeners[type]) return;
  var i = 0;
  while (i < this.selfEventListeners[type].length) if (this.selfEventListeners[type][i] == fkt) this.selfEventListeners[type].splice(i, 1); else i++;
  if (this.selfEventListeners[type].length == 0) delete this.selfEventListeners[type];
 },

 callEventListener : /* protected */ function (type, param) {
  try { // try notwendig, weil Fenster durch einen EventListener freigegeben werden koennte
   if (this.selfEventListeners[type]) for (var i = 0; i < this.selfEventListeners[type].length; i++) this.selfEventListeners[type][i](this, param);
   if (this.mgr && this.mgr.eventListeners[type]) for (var i = 0; i < this.mgr.eventListeners[type].length; i++) this.mgr.eventListeners[type][i](this, param);
  } catch (e) {}
 },

 disable : /* public */ function () {
  if (this.freed) throw 'Object is freed';
  if (this.disabledCount == 0) {
   this.el['Disabled'] = document.createElement('div');
   this.el['Disabled'].className = 'JSW Disabled';
   this.el['OuterBox'].appendChild(this.el['Disabled']);
  }
  this.disabledCount++;
 },

 enable : /* public */ function () {
  if (this.freed) throw 'Object is freed';
  this.disabledCount--;
  if (this.disabledCount <= 0) {
   this.disabledCount = 0;
   this.el['OuterBox'].removeChild(this.el['Disabled']);
  }
 },
 
 hiddenCover : /* protected */ function (covered) {
  if (covered) {
   if (this.el['FrameCover']) return;
   this.el['FrameCover'] = document.createElement('div');
   this.el['FrameCover'].className = 'JSW FrameCover';
   this.el['OuterBox'].appendChild(this.el['FrameCover']);
  } else if (this.el['FrameCover']) {
   this.el['OuterBox'].removeChild(this.el['FrameCover']);
   this.el['FrameCover'] = null;
  }
 },

 showFrameload : /* public */ function (parent) {
  if (this.freed) throw 'Object is freed';
  if (this.appended) return;
  if (parent) this.parentElement = parent;
  this.el['OuterBox'].style.visibility = 'hidden';
  this.parentElement.appendChild(this.el['OuterBox']);
  this.appended = true;
 },

 show : /* public */ function (parent) {
  if (this.freed) throw 'Object is freed';
  JSWEffect_terminate(this); // falls gerade ein hide-Effekt laeuft, muss dieser beendet werden, damit appended auf false gesetzt wird, bevor show durchlaeuft!
  if ((this.visible && (!parent || parent == this.parentElement)) || (!this.parentElement && !parent)) return;
  if (parent) {
    if (this.parentElement && (this.parentElement != parent)) this.appended = false;
    this.parentElement = parent;
  }
  this.visible = true;
  if (!this.excluded) this.el['OuterBox'].style.visibility = 'hidden';
  if (!this.appended) {
   if (!this.parentElement) throw 'Parent element of the window is not specified!';
   try { this.parentElement.appendChild(this.el['OuterBox']); }
   catch (e) {
    // Fuer IE: Alle Elemente neu erstellen statt umhaengen
    this.parentElement.innerHTML = this.el['OuterBox'].outerHTML;
    var oldEl = this.el;
    this.el = new Object();
    this.el['OuterBox'] = this.parentElement.getElementsByTagName('div')[0];
    var found;
    do {
     found = false;
     for (var key in oldEl) {
      if (this.el[key]) continue;
      var n = oldEl[key].nodeName;
      for (var i = 0; i < oldEl['OuterBox'].getElementsByTagName(n).length; i++) if (oldEl['OuterBox'].getElementsByTagName(n)[i] == oldEl[key]) {
       this.el[key] = this.el['OuterBox'].getElementsByTagName(n)[i];
       found = true;
 	   break;
	  }
     }
    } while (found);
   } 
   this.appended = true;
  }
  if (!this.excluded) {
   this.setPos();
   if (this.effects && this.effects['Show']) this.effects['Show'](this, this.effects['duration'], null, this.effects['ShowParams']);
   else this.el['OuterBox'].style.visibility = 'visible';
  }
  this.documentResize();
  this.callEventListener('show');
  this.callEventListener('move');
 },

 hide : /* public */ function () {
  if (this.freed) throw 'Object is freed';
  if (!this.visible || !this.closable) return;
  this.visible = false;
  if (this.excluded) {
   this.excludedWindow.close();
   return;
  }
  var onEffectTerminate = function (win) {
   win.el['OuterBox'].style.visibility = 'hidden';
   win.callEventListener('hide');
   if (win.parentElement /* ToDo: wenn win.effects = null tritt hier ohne if ein Fehler auf */) win.parentElement.removeChild(win.el['OuterBox']);
   win.appended = false;
   var b = win.freeOnHide;
   if (b) win.free();
   return b;
  }
  if (this.effects && this.effects['Hide']) this.effects['Hide'](this, this.effects['duration'], onEffectTerminate, this.effects['HideParams']);
  else window.setTimeout(onEffectTerminate, 0, this);
 },

 setPos : /* public */ function (newPos) { // Wendet den in Pos gespeicherten Style auf OuterBox an
  // Hinweis: Neben setPos greift auch mouseMove:applyChange auf die Positionsstyles von OuterBox zu!
  if (this.freed) throw 'Object is freed';
  var pw = this.parentOffsetWidth();
  var ph = this.parentOffsetHeight();
  if (newPos) {
   var _this = this;
   var i, s;
   var rect = function (site) { if (site == -1) return 0; if (_this.minimalVisible[site] < 0) return 0; else return _this.minimalVisible[site]; }
   var interpret = function (type, ps, site) {
    i = newPos.indexOf(';' + type + ':');
    if (i == -1) _this.pos[type] = Number.NaN; else {
     s = newPos.substring(i+2+type.length, newPos.indexOf(';', i+2+type.length));
     if (s.indexOf('%') == -1) _this.pos[type+'Percent'] = false; else { s = ps*parseFloat(s)/100; _this.pos[type+'Percent'] = true; }
     _this.pos[type] = parseFloat(s) + rect(site);
    }
   }
   newPos = ';'+newPos.split(' ').join('');
   interpret('top', ph, 0);
   interpret('left', pw, 1);
   interpret('right', pw, 2);
   interpret('bottom', ph, 3);
   interpret('width', pw, -1);
   interpret('height', ph, -1);
   i = newPos.indexOf(';position:'); if (i >= 0 && newPos.substring(i+10, newPos.indexOf(';', i+10)).indexOf('fixed') >= 0) this.pos.position = 'fixed'; else this.pos.position = 'absolute';
  }
  if (this.excluded) {
   // ToDo
   return;
  }
  if (!this.appended) return;
  if (!this.pos['position']) this.pos['position'] = 'absolute';
  this.el['OuterBox'].style.position = this.pos['position'];
  if (this.maximized) {
   this.el['OuterBox'].style.top = ((this.minimalVisible[0] > 0)?this.minimalVisible[0]:0) + 'px';
   this.el['OuterBox'].style.left = ((this.minimalVisible[1] > 0)?this.minimalVisible[1]:0) + 'px';
   this.el['OuterBox'].style.right = ((this.minimalVisible[2] > 0)?this.minimalVisible[2]:0) + 'px';
   this.el['OuterBox'].style.bottom = ((this.minimalVisible[3] > 0)?this.minimalVisible[3]:0) + 'px';
   this.el['OuterBox'].style.width = 'auto';
   this.el['OuterBox'].style.height = 'auto';
   return;
  }
  this.el['OuterBox'].style.top    = (isNaN(this.pos['top']))   ?'auto':((this.pos['topPercent'])   ?(this.pos['top']    / ph * 100 + '%'):(this.pos['top']    + 'px'));
  this.el['OuterBox'].style.left   = (isNaN(this.pos['left']))  ?'auto':((this.pos['leftPercent'])  ?(this.pos['left']   / pw * 100 + '%'):(this.pos['left']   + 'px'));
  if (!this.autoWidth  || isNaN(this.pos.left))  this.el['OuterBox'].style.right  = (isNaN(this.pos['right'])) ?'auto':((this.pos['rightPercent']) ?(this.pos['right']  / pw * 100 + '%'):(this.pos['right']  + 'px'));
  else this.el['OuterBox'].style.right = 'auto';
  if (!this.autoHeight || isNaN(this.pos.top)) this.el['OuterBox'].style.bottom = (isNaN(this.pos['bottom']))?'auto':((this.pos['bottomPercent'])?(this.pos['bottom'] / ph * 100 + '%'):(this.pos['bottom'] + 'px'));
  else this.el['OuterBox'].style.bottom = 'auto';
  if (!this.autoWidth)  this.el['OuterBox'].style.width  = (isNaN(this.pos['width'])) ?'auto':((this.pos['widthPercent']) ?(this.pos['width']  / pw * 100 + '%'):(this.pos['width']  + 'px'));
  if (!this.autoHeight) this.el['OuterBox'].style.height = (isNaN(this.pos['height']))?'auto':((this.pos['heightPercent'])?(this.pos['height'] / ph * 100 + '%'):(this.pos['height'] + 'px'));
  this.callEventListener('move');
 },

 getWindowPos : /* protected */ function () { // Returns an Array, that contains the Position of OuterBox, seen from the inner Window
  if (this.freed) throw 'Object is freed';
  var pos;
  if (window.getComputedStyle(this.el['OuterBox']).position == 'fixed') pos = new Array(this.el['OuterBox'].offsetLeft, this.el['OuterBox'].offsetTop);
  else pos = new Array(this.offsetLeftFrom(this.el['OuterBox'], document.body) - window.pageXOffset, this.offsetTopFrom(this.el['OuterBox'], document.body) - window.pageYOffset);
  return pos;
 },

 hasAtr : /* private */ function (el, atr) {
  if (!el) return false;
  if ((' '+el.className+' ').indexOf(' '+atr+' ') >= 0) return true;
  else return false;
 },

 setAtr : /* private */ function (el, atr) {
  if (!el) return;
  if ((' '+el.className+' ').indexOf(' '+atr+' ') >= 0) return;
  el.className += ' '+atr;
 },

 rmAtr : /* private */ function (el, atr) {
  if (!el) return;
  var a = el.className.split(' ');
  var s = '';
  for (var i = 0; i < a.length; i++) {
   if (!a[i] || a[i] == atr) continue;
   if (i > 0) s += ' ';
   s += a[i];
  }
  el.className = s;
 },

 setOrRmAtr : /* private */ function (el, atr, set) { if (this.freed) throw 'Object is freed'; if (set) this.setAtr(el, atr); else this.rmAtr(el, atr); },

 onEvent : /* private */ function (el, event, fkt, bubbles) { // provides easy eventListeners. el: Element to set the listener; event: string-name of the event(without "on"); fkt: a Function to call if the event occours, fkt is called in the scope of _this
  if (!el) return;
  var _this = this;
  var oev = new Object();
  oev['f'] = function (ev) {
    // Browseruebergreifende Kompatibilitaet
    if (!ev) ev = window.event;
    if (!ev.target) ev.target = ev.srcElement;
    if (!ev.offsetX && ev.pageX) {
     ev.offsetX = ev.pageX - _this.offsetLeftFrom(ev.target, document.body);
     ev.offsetY = ev.pageY - _this.offsetTopFrom(ev.target, document.body);
    }
    fkt.call(_this, ev);
   }
  oev['event'] = event;
  oev['el'] = el;
  el.addEventListener(event, oev['f'], bubbles);
  this.eventListeners.push(oev);
  return oev;
 },

 rmEvent : function (oev) { // oev wird von onEvent zurueckgegeben
  var nr = oev;
  if (isNaN(nr)) {
   nr = 0;
   while (nr < this.eventListeners.length) if (this.eventListeners[nr] == oev) break; else nr++;
   if (nr >= this.eventListeners.length || this.eventListeners[nr] != oev) return;
  } else {
   if (nr < 0 || nr >= this.eventListeners.length) return;
   oev = this.eventListeners[nr];
  }
  if (document.removeEventListener) oev['el'].removeEventListener(oev['event'], oev['f'], false); else oev['el'].detachEvent('on'+oev['event'], oev['f']);
  this.eventListeners.splice(nr, 1);
 },

 actualizePos : /* private */ function () { // falls prozentuale Angaben oder autoHeight/autoWidth verwendet werden, wird die Pixelposition neu berechnet
  // Falls prozentuale Angaben verwendet werden, Position aktualisieren
  if (!this.visible || this.excluded || this.minimized || this.maximized) return;
  var style = null;
  var _this = this;
  function checkStyle (type) {
   if (isNaN(_this.pos[type])) return;
   if (!style) style = window.getComputedStyle(_this.el['OuterBox']);
   _this.pos[type] = parseInt(style[type]);
  }
  checkStyle('top');
  checkStyle('left');
  checkStyle('right');
  checkStyle('bottom');
  checkStyle('width');
  checkStyle('height');
 },

 offsetLeftFrom : /* private */ function (el, offsetEl) { // Ermittelt den Linken Abstand eines Elements bis zu einem bestimmten Eltern-ELement
  var r = 0;
  do {
   r += el.offsetLeft;
   el = el.offsetParent;
  } while (el && el != offsetEl);
  return r;
 },

 offsetTopFrom : /* private */ function (el, offsetEl) { // Ermittelt den Oberen Abstand eines Elements bis zu einem bestimmten Eltern-ELement
  var r = 0;
  do {
   r += el.offsetTop;
   el = el.offsetParent;
  } while (el && el != offsetEl);
  return r;
 },

 parentOffsetWidth : /* private */ function () { // Gibt die Breite des fuer das Fenster verfuegbaren Anzeigebereiches zurueck
  if (this.excluded) return screen.availWidth;
  if (!this.el['OuterBox'].offsetParent || this.el['OuterBox'].offsetParent == document.body) return window.innerWidth;
  else return this.el['OuterBox'].offsetParent.offsetWidth;
 },

 parentOffsetHeight : /* private */ function () { // Gibt die Hoehe des fuer das Fenster verfuegbaren Anzeigebereiches zurueck
  if (this.excluded) return screen.availHeight;
  if (!this.el['OuterBox'].offsetParent || this.el['OuterBox'].offsetParent == document.body) return window.innerHeight;
  else return this.el['OuterBox'].offsetParent.offsetHeight;
 },

 offsetTop : /* private */ function () { // Gibt den Abstand von oben bis zum offsetParent des normalisierten Fensters in Pixeln zurueck
  if (!isNaN(this.pos.top)) return this.pos.top;
  return this.parentOffsetHeight() - this.pos.height - this.pos.bottom;
 },

 offsetLeft : /* private */ function () { // Gibt den Abstand von links bis zum offsetParent des normalisierten Fensters in Pixeln zurueck
  if (!isNaN(this.pos.left)) return this.pos.left;
  return this.parentOffsetWidth() - this.pos.width - this.pos.right;
 },

 offsetWidth : /* private */ function () { // Gibt die Breite des normalisierten Fensters in Pixeln zurueck
  if (!isNaN(this.pos.width)) return this.pos.width;
  return this.parentOffsetWidth() - this.pos.left - this.pos.right;
 },

 offsetHeight : /* private */ function () { // Gibt die Hoehe des normalisierten Fensters in Pixeln zurueck
  if (!isNaN(this.pos.height)) return this.pos.height;
  return this.parentOffsetHeight() - this.pos.top - this.pos.bottom;
 },

 setOffsetPosition : /* public */ function (top, left, width, height) { // rechnet die gegebenen Parameter auf die Positionierung des Fensters um, sodass Anker und prozentuale Angaben erhalten bleiben
  if (this.freed) throw 'Object is freed';
  if (!this.visible || this.maximized || this.minimized) return;
  if (this.excluded) {
   // ToDo
   return;
  }
  var pw = this.parentOffsetWidth();
  var ph = this.parentOffsetHeight();
  if (!isNaN(this.pos['top']))    this.pos['top'] = top;
  if (!isNaN(this.pos['left']))   this.pos['left'] = left;
  if (!isNaN(this.pos['right']))  this.pos['right'] = (isNaN(pw))?0:(pw - width - left);
  if (!isNaN(this.pos['bottom'])) this.pos['bottom'] = (isNaN(ph))?0:(ph - height - top);
  if (!isNaN(this.pos['width']))  this.pos['width'] = width;
  if (!isNaN(this.pos['height'])) this.pos['height'] = height;
  this.setPos();
 },

 mouseDown : /* private */ function (ev) {
  if (ev.button && ev.button != 0) return;
  this.lastMouseDown = ev;
  if (this.maximized) return;
  // Aktion fuer move und resize einrichten
  var p = ev.target;
  var target = p;
  ev.target = null;
  do {
   p = p.parentElement;
   if (p == this.el['Bar'] || p == this.el['Buttons']) {
    target = p;
    break;
   }
  } while (p);
  var b = false;
  if ((target == this.el['EdgeTopLeft'] || target == this.el['EdgeTopRight'] || target == this.el['EdgeBottomLeft'] || target == this.el['EdgeBottomRight']) && this.resizable) { this.autoHeight = false; this.autoWidth = false; b = true; }
  else if ((target == this.el['BorderTop'] || target == this.el['BorderBottom']) && this.resizable) { this.autoHeight = false; b = true; }
  else if ((target == this.el['BorderLeft'] || target == this.el['BorderRight']) && this.resizable) { this.autoWidth = false; b = true; }
  else if (target == this.el['Bar'] && this.movable) b = true;
  if (b) { // Ein Element fuer resize/move wurde angeklickt
   this.actualizePos();
   // Startposition festhalten
   this.startPos = clone(this.pos);
   this.startPos['mausX'] = ev.clientX;
   this.startPos['mausY'] = ev.clientY;
   this.startPos['target'] = target;
   // Cursor-Element und Events setzen
   this.hiddenCover(true);
   this.el['FrameCover'].style.margin = '-50px';
   this.startPos['oldMouseDown'] = document.onmousedown;
   document.onmousedown = function () { return false; }
   this.startPos['mouseUpOev'] = this.onEvent(document, 'mouseup', this.mouseUp);
   this.startPos['mouseMoveOev'] = this.onEvent(document, 'mousemove', this.mouseMove, true);
  }
 },

 documentResize : /* private */ function () {
  if (!this.visible || this.excluded || this.maximized || this.minimized) return;
  // falls ausserhalb von Anzeigebereich, zuruecksetzen
  if (this.minimalVisible) {
   if (this.minimalVisible[0] >= 0) { if (this.el['OuterBox'].offsetTop < this.minimalVisible[0]) this.setOffsetPosition(this.minimalVisible[0], this.el['OuterBox'].offsetLeft, this.el['OuterBox'].offsetWidth, this.el['OuterBox'].offsetHeight); }
   else { /* ToDo */ }
   if (this.minimalVisible[1] >= 0) { /* ToDo */ }
   else { if (this.el['OuterBox'].offsetLeft + this.el['OuterBox'].offsetWidth < - this.minimalVisible[1]) this.setOffsetPosition(this.el['OuterBox'].offsetTop, - this.minimalVisible[1] - this.el['OuterBox'].offsetWidth, this.el['OuterBox'].offsetWidth, this.el['OuterBox'].offsetHeight); }
   if (this.minimalVisible[2] >= 0) { /* ToDo */ }
   else { if (this.el['OuterBox'].offsetLeft > this.parentOffsetWidth() + this.minimalVisible[2] && (window.getComputedStyle(this.el['OuterBox'].offsetParent).overflow == 'hidden' || this.pos.position == 'fixed')) this.setOffsetPosition(this.el['OuterBox'].offsetTop, this.parentOffsetWidth() + this.minimalVisible[2], this.el['OuterBox'].offsetWidth, this.el['OuterBox'].offsetHeight); }
   if (this.minimalVisible[3] >= 0) { /* ToDo */ }
   else { if (this.el['OuterBox'].offsetTop > this.parentOffsetHeight() + this.minimalVisible[3] && (window.getComputedStyle(this.el['OuterBox'].offsetParent).overflow == 'hidden' || this.pos.position == 'fixed')) this.setOffsetPosition(this.parentOffsetHeight() + this.minimalVisible[3], this.el['OuterBox'].offsetLeft, this.el['OuterBox'].offsetWidth, this.el['OuterBox'].offsetHeight); }
  }
 },

 mouseUp : /* private */ function (ev) {
  if (this.startPos) {
   // Move-Events und Einstellungen zuruecknehmen
   this.el['FrameCover'].style.margin = '0px';
   this.hiddenCover(false);
   this.rmEvent(this.startPos['mouseUpOev']);
   this.rmEvent(this.startPos['mouseMoveOev']);
   document.onmousedown = this.startPos['oldMouseDown'];
   this.startPos = null;
   this.documentResize();
  }
 },

 mouseMove : /* private */ function (ev) {
  if (!this.startPos) return;
  // OuterBox bewegen
  var _this = this;
  function applyChange (type, horizontal, invert) {
   _this.pos[type] = _this.startPos[type] + (-_this.startPos['maus'+(horizontal?'X':'Y')] + (horizontal?ev.clientX:ev.clientY)) * (invert?(-1):(1));
   if (_this.startPos[type+'Percent']) {
    var size;
    size = (horizontal?_this.parentOffsetWidth():_this.parentOffsetHeight());
    _this.el['OuterBox'].style[type] = _this.pos[type] / size * 100 + '%';
   } else _this.el['OuterBox'].style[type] = _this.pos[type] + 'px';
  }
  if (this.startPos['target'] == this.el['Bar']) {
   if (isNaN(this.startPos['right'])) { applyChange('left', true, false); }
   else if (isNaN(this.startPos['left'])) { applyChange('right', true, true); }
   else if (isNaN(this.startPos['width'])) { applyChange('left', true, false); if (!this.autoWidth) applyChange('right', true, true); }
   if (isNaN(this.startPos['bottom'])) { applyChange('top', false, false); }
   else if (isNaN(this.startPos['top'])) { applyChange('bottom', false, true); }
   else if (isNaN(this.startPos['height'])) { applyChange('top', false, false); if (!this.autoHeight) applyChange('bottom', false, true); }
  }
  if (this.startPos['target'] == this.el['BorderTop'] || this.startPos['target'] == this.el['EdgeTopLeft'] || this.startPos['target'] == this.el['EdgeTopRight']) {
   if (isNaN(this.startPos['bottom'])) { applyChange('top', false, false); applyChange('height', false, true); }
   else if (isNaN(this.startPos['top'])) { applyChange('height', false, true); }
   else if (isNaN(this.startPos['height'])) { applyChange('top', false, false); }
   this.autoHeight = false;
  }
  if (this.startPos['target'] == this.el['BorderLeft'] || this.startPos['target'] == this.el['EdgeTopLeft'] || this.startPos['target'] == this.el['EdgeBottomLeft']) {
   if (isNaN(this.startPos['right'])) { applyChange('left', true, false); applyChange('width', true, true); }
   else if (isNaN(this.startPos['left'])) { applyChange('width', true, true); }
   else if (isNaN(this.startPos['width'])) { applyChange('left', true, false); }
   this.autoWidth = false;
  }
  if (this.startPos['target'] == this.el['BorderRight'] || this.startPos['target'] == this.el['EdgeTopRight'] || this.startPos['target'] == this.el['EdgeBottomRight']) {
   if (isNaN(this.startPos['right'])) { applyChange('width', true, false); }
   else if (isNaN(this.startPos['left'])) { applyChange('width', true, false); applyChange('right', true, true); }
   else if (isNaN(this.startPos['width'])) { applyChange('right', true, true); }
   this.autoWidth = false;
  }
  if (this.startPos['target'] == this.el['BorderBottom'] || this.startPos['target'] == this.el['EdgeBottomLeft'] || this.startPos['target'] == this.el['EdgeBottomRight']) {
   if (isNaN(this.startPos['bottom'])) { applyChange('height', false, false); }
   else if (isNaN(this.startPos['top'])) { applyChange('height', false, false); applyChange('bottom', false, true); }
   else if (isNaN(this.startPos['height'])) { applyChange('bottom', false, true); }
   this.autoHeight = false;
  }
  this.callEventListener('move');
 },

 exclude : /* public */ function (click) {
  if (this.freed) throw 'Object is freed';
  if (!this.excludable || this.excluded) return;
  // Fenster oeffnen
  var p = this.getWindowPos();
  var pos = new Array(this.el['OuterBox'].offsetWidth, this.el['OuterBox'].offsetHeight, p[0], p[1]);
  var w = window.open('', '', 'width='+pos[0]+',height='+pos[1]+',left='+pos[2]+',top='+pos[3]);
  if (!w) return; // Popup blockiert!
  if (click) {
   if (window.opera) { // Nur im echten Opera kann die Position pixelgenau berechnet werden!
    var zoom = pos[0] / w.innerWidth;
    pos[2] = pos[2] * zoom + (w.outerWidth - w.innerWidth * zoom) / 2;
    pos[3] = pos[3] * zoom + w.outerHeight - w.innerHeight * zoom - (w.outerWidth - w.innerWidth * zoom) / 2;
    pos[0] = pos[0] * zoom;
    pos[1] = pos[1] * zoom;
    w.resizeTo(pos[0], pos[1]);
   } else if (w.innerWidth > 0) {
    var zoom = w.innerWidth / pos[0]; // Annahme: Neues Fenster hat gleichen Zoomfaktor, wie Hauptfenster
    pos[2] = this.lastMouseDown.screenX - (this.lastMouseDown.clientX - pos[2]) * zoom;
    pos[3] = this.lastMouseDown.screenY - (this.lastMouseDown.clientY - pos[3]) * zoom;
   }
   w.moveTo(pos[2], pos[3]);
  }
  this.excludedWindow = w;
  // Fenster umhaengen
  this.parentElement.removeChild(this.el['OuterBox']);
  this.appended = false;
  this.el['OuterBox'].className += ' excluded';
  this.el['OuterBox'].style.position = 'absolute';
  this.el['OuterBox'].style.top = '0px';
  this.el['OuterBox'].style.left = '0px';
  this.el['OuterBox'].style.width = '100%';
  this.el['OuterBox'].style.height = '100%';
  for (var i = 0; i < this.el['OuterBox'].childNodes.length; i++)
   if (this.el['OuterBox'].childNodes[i].nodeType == 1)
    this.el['OuterBox'].childNodes[i].style.display = 'none';
  this.el['InnerBox'].style.display = 'block';
  this.el['InnerBox'].style.position = 'absolute';
  this.el['InnerBox'].style.top = '0px';
  this.el['InnerBox'].style.left = '0px';
  this.el['InnerBox'].style.right = '0px';
  this.el['InnerBox'].style.bottom = '0px'; 
  w.document.title = this.el['Title'].innerHTML;
  var sty = document.getElementsByTagName('head')[0].getElementsByTagName('link');
  for (var i = 0; i < sty.length; i++) {
   if (sty[i].rel.toLowerCase() != 'stylesheet') continue;
   var cloneSty = document.createElement('link');
   cloneSty.rel = 'stylesheet';
   cloneSty.href = sty[i].href;
   w.document.getElementsByTagName('head')[0].appendChild(cloneSty);
  }
  sty = document.getElementsByTagName('head')[0].getElementsByTagName('style');
  for (var i = 0; i < sty.length; i++)
   w.document.getElementsByTagName('head')[0].innerHTML += sty[i].outerHTML;
  this.excluded = true;
  this.show(w.document.body);
  var _this = this;
  this.onEvent(w, 'beforeunload', function () { _this.free(); });
  this.excludedClosedTimer = window.setInterval(function () { if (w.closed) _this.free(); }, 100);
  this.callEventListener('exclude');
 },

 maximize : /* public */ function () {
  if (this.freed) throw 'Object is freed';
  if (!this.maximizable) return;
  if (this.excluded) {
   // Todo
   return;
  }
  this.maximized = true;
  var t = (this.minimalVisible[0] > 0)?this.minimalVisible[0]:0;
  var l = (this.minimalVisible[1] > 0)?this.minimalVisible[1]:0;
  var r = (this.minimalVisible[2] > 0)?this.minimalVisible[2]:0;
  var b = (this.minimalVisible[3] > 0)?this.minimalVisible[3]:0;
  var onEffectTerminate = function (win) {
   win.el['OuterBox'].style.top = t+'px';
   win.el['OuterBox'].style.left = l+'px';
   win.el['OuterBox'].style.right = r+'px';
   win.el['OuterBox'].style.bottom = b+'px';
   win.el['OuterBox'].style.width = 'auto';
   win.el['OuterBox'].style.height = 'auto';
   win.el['OuterBox'].style.position = (this.parentElement == document.body)?'fixed':'absolute';
   win.setAtr(win.el['OuterBox'], 'maximized');
   win.callEventListener('move');
  }
  if (this.visible && this.effects && this.effects['Maximize']) this.effects['Maximize'](this, this.effects['duration'], onEffectTerminate, t, l, this.parentOffsetWidth()-r, this.parentOffsetHeight()-b, this.effects['MaximizeParams']);
  else onEffectTerminate(this);
  this.callEventListener('maximize');
 },

 normalize : /* public */ function () {
  if (this.freed) throw 'Object is freed';
  if (!this.visible) { this.maximized = false; return; }
  if (this.excluded) {
   // ToDo
   return;
  }
  var onEffectTerminate = function (win) {
   win.maximized = false;
   win.rmAtr(win.el['OuterBox'], 'maximized');
   win.setPos();
  }
  var fixed = this.pos['position'] == 'fixed';
  if (this.effects  && this.effects['Normalize']) this.effects['Normalize'](this, this.effects['duration'], onEffectTerminate, this.offsetTop() - ((fixed)?0:window.pageYOffset), this.offsetLeft() - ((fixed)?0:window.pageXOffset), this.offsetWidth(), this.offsetHeight(), this.effects['NormalizeParams']);
  else onEffectTerminate(this);
  this.callEventListener('normalize');
 },

 minimize : /* public */ function () {
  if (this.freed) throw 'Object is freed';
  if (!this.visible || !this.minimizable) return;
  if (this.excluded) {
   // ToDo
   return;
  }
  this.minimized = true;
  var p = this.minimizePoint();
  var onEffectTerminate = function (win) {
   win.el['OuterBox'].style.visibility = 'hidden';
  }
  if (this.effects  && this.effects['Minimize']) this.effects['Minimize'](this, this.effects['duration'], onEffectTerminate, p[0], p[1], this.effects['MinimizeParams']);
  else onEffectTerminate(this);
  this.callEventListener('minimize');
 },

 unminimize : /* public */ function () {
  if (this.freed) throw 'Object is freed';
  if (!this.visible || !this.minimized) return;
  if (this.excluded) {
   // ToDo
   return;
  }
  var p = this.minimizePoint();
  var onEffectTerminate = function (win) {
   win.minimized = false;
   win.el['OuterBox'].style.visibility = 'visible';
  }
  if (this.effects && this.effects['Unminimize']) this.effects['Unminimize'](this, this.effects['duration'], onEffectTerminate, p[0], p[1], this.effects['UnminimizeParams']);
  else onEffectTerminate(this);
  this.callEventListener('unminimize');
 },

 free : /* public */ function () {
  try {
   if (this.excludedClosedTimer) window.clearInterval(this.excludedClosedTimer);
   for (var i = this.eventListeners.length-1; i >= 0; i--) this.rmEvent(i);
   JSWEffect_terminate(this);
   if (this.scrollRectListener) this.scrollRectListener.free();
   if (this.appended) this.parentElement.removeChild(this.el['OuterBox']);
  } catch (e) {}
  this.callEventListener('free');
  this.freed = true;
  for (var key in this) if (typeof this[key] == 'object') this[key] = null;
 }
}
