//Configure abaixo:
//winDigTitleBarHeight: Altura da TitleBar
//winDigStatusHeight: Altura da Statusbar
//nCascateWinDigs: Número de janelas em cascata
var winDigTitleBarHeight=31, winDigStatusHeight=3, nCascateWinDigs=5;

var curWinDigHeightDiff=winDigTitleBarHeight +winDigStatusHeight; var curWinDigN=0, curWinDigZ=50;

/* ## Início da classe _windig_ ## */
var windig, windigs=[];
windig=function(tName, tTitle, tAddr, x, y, w, h, props) {
  //Criar div "comporter" das janelas, caso ainda não exista.
  createWinDigsComporter();

  //Tratar propriedades
  if (props) { var prop, n=(props=props.split(',')).length;
    for (; prop=props[--n]; ) {
      if (prop.replace(' ', '')=='noresize') { this.redimensionavel=0; }
      if (prop.replace(' ', '')=='nominimize') { this.minimizavel=0; }
      if (prop.replace(' ', '')=='noscroll') { this.temScroll=0; }
      if (prop.replace(' ', '')=='htmltitle') { this.htmlTitle=1; }
      if (prop.replace(' ', '')=='unique') {
        if (winDigExists(tName)) {
          if (windigs[tName].minimizada) windigs[tName].restore(); //Se estiver minimizada, restaurar
          windigs[tName].getFocus(); //Fazer a janela tomar foco
          return windigs[tName]; //Retornar a instância
        }
      }
    }
  }
  this.title=tTitle; this.tWin=this.createWin(x, y, w, h, tAddr); curWinDigN++; this.tName=tName;
  this.getFocus(); windigs[tName]=this;
}
windig.prototype={
  lastClickTime: 99999999999,
  lastClickCoord: [9999, 9999],
  maximizedTime: 0,
  minimizada: 0,
  telacheia: 0,
  moldura: null,
  resizing: [],
  minimizavel: 1,
  redimensionavel: 1,
  temScroll: 1,
  htmlTitle: 0,

  createID: function() { return Math.random().toString().substring(2); },

  createWin: function(x, y, w, h, tAddr) { //Função construtora da class
    var nE, nB, nC, nF, rX, rY, rZ; //novoElemento, novoBotão, novoContent, novoFrame, resizeX, resizeY, resizeZ
    var scrollPos=getScrollPos(); //Posição X/Y da rolagem (retorna array associativo)
    nE=cE('div', ['id='+ this.createID(), 'className=windig'],
      [
        cE('div', 'className=titlebar', cE('span', 'unselectable=on', this.title) ),
        nB=cE('div', 'className=botoes',
          [
            cE('a', 'className=min', '_'),
            cE('a', 'className=max', 'O'),
            cE('a', 'className=close', 'X')
          ]
        ),
        nC=cE('div', 'className=fundo1', cE('div', 'className=fundo2', cE('div', 'className=fundo3', cE('div', 'className=fundo4',
            nF=cE('iframe', ['frameBorder=0', 'border=0'], '')
        )))),
        cE('div', 'className=borda1', ''),     cE('div', 'className=borda2', ''),
        cE('div', 'className=borda3', ''),     cE('div', 'className=borda4', ''),
        rX=cE('div', 'className=resizer resizex', ' '),
        rY=cE('div', 'className=resizer resizey', ' '),
        rZ=cE('div', 'className=resizer resizez', ' ')
      ]
    );
    if (!x) x=(curWinDigN %nCascateWinDigs) *30; if (!y) y=(curWinDigN %nCascateWinDigs) *30;
    x+=scrollPos['x']; y+=scrollPos['y']; nE.style.left=x +'px'; nE.style.top=y +'px';
    if (!w) w=500; if (!h) h=400;
    nE.style.width=w +'px'; nE.style.height=h +'px';
    /* Altura do frame interno */ nF.style.height=h -curWinDigHeightDiff +'px';
    this.wReference=nE; this.fReference=nF; nE._this=this; nB=nB.getElementsByTagName('a');
    nB['min']=nB[0]; nB['max']=nB[1]; nB['close']=nB[2];
    if (this.htmlTitle) { this.setTitle(this.title, 1); } //Título em HTML

    adEvento(nB['min'], 'click', this.minimize.bindAsEventListener(this) );
    adEvento(nB['max'], 'click', this.maximize.bindAsEventListener(this) );
    adEvento(nB['close'], 'click', this.close.bindAsEventListener(this) );
    adEvento(nE.firstChild, 'dblclick', this.maximize.bindAsEventListener(this) );
    adEvento(nE.firstChild, 'mousedown', this.startDrag.bindAsEventListener(this) );
    adEvento([ rX, rY, rZ ], 'mousedown', this.startResize.bindAsEventListener(this) );

    if (!this.minimizavel) { rEs(nB['min']); }
    if (!this.redimensionavel) { rEs(nB['max']); rEs(nE.lastChild); rEs(nE.lastChild); rEs(nE.lastChild); }
    if (!this.temScroll) { this.fReference.scrolling='no'; }

    nF.name=nF.id='tf'+ nE.id; nE.unselectable='on';
    gE('windigs').appendChild(nE); nF.contentWindow.document.location.href=tAddr;

    //Isso abaixo faz sentido pra você?! Nem pra mim. Mas sem isso o IE dá a louca.
    nF.style.width=nF.offsetWidth +'px';

    /* Tentar adicionar evento para tomar foco ao documento de dentro do IFrame */
    window.setTimeout(
      function() { var _this=this;
        return function() {
          try { adEvento(nF.contentWindow.document, 'focus', _this.getFocus.bindAsEventListener(_this)); } catch(e) { }
        }
      }.apply(this)
    , 1500);

    return this;
  },


  /* ## Métodos auxiliares */
  //Cria camada sobre todo o documento, para evitar perda dos eventos devido ao uso de frames
  createDraggerArea: function(cN) { var tDA;
    document.body.appendChild(  tDA=cE('div', ['id=draggerarea', 'className='+ cN], '')  );
    adEvento(tDA, 'click', this.removeDraggerAndFrame.bindAsEventListener(this));
  },
  //Força a remoção da camada de bloqueio caso haja algum bug (no click)
  removeDraggerAndFrame: function() {
    //Os whiles aqui são preventivos, para evitar bugs caso sejam criadas duas molduras ou duas áreas de arrastar
    while (gE('draggerarea')) rEs( gE('draggerarea') ); while (gE('molduradrag')) rEs(gE('molduradrag'));
    return true;
  },
  //Cria moldura para ser arrastada, no lugar de toda a janela
  createFrame: function() { var tM, tE=this.wReference; var titulo=tE.firstChild.firstChild.firstChild.nodeValue;
    tM=cE('div', ['id=molduradrag', 'unselectable=on'],
      [
        cE('div', 'className=titlebar', cE('span', titulo)),
        cE('div', 'className=fundo1',
          cE('div', 'className=fundo2', cE('div', 'className=fundo3', cE('div', 'className=fundo4', '')))
        ),
        cE('div', 'className=borda1', ''),   cE('div', 'className=borda2', ''),
        cE('div', 'className=borda3', ''),   cE('div', 'className=borda4', '')
      ]
    );
    with(tM.style) { width=tE.offsetWidth +'px'; height=tE.offsetHeight +'px'; top=tE.offsetTop +'px'; left=tE.offsetLeft +'px'; }
    document.body.appendChild(tM); return tM;
  },
  //Ajusta altura do iFrame dentro de uma janela
  adjustIFrameHeight: function() {
    try { var oldScroll=this.fReference.contentWindow.document.body.scrollTop; } catch(e) { var oldScroll=0; }
    this.fReference.style.height='1px'; nH=this.wReference.offsetHeight;
    this.fReference.style.height=nH -curWinDigHeightDiff +'px';
    try { this.fReference.contentWindow.document.body.scrollTop=oldScroll; } catch(e) { }
    return true;
  },
  //Retorna o número de janelas maximizadas
  getNMinWindows: function() { var tWins, nMinWindows=0, i=0, n=(tWins=gE('windigs').childNodes).length;
    for ( ; i<n; i++) { if (hasTok(tWins[i].className, 'minimizada', ' ')) nMinWindows++; } return nMinWindows;
  },


  /* ## Métodos para arrastar */
  startDrag: function(e) { this.getFocus(); e=(e||event); if ((e.which || e.button) != 1) return false;
    var tE, evXY; tE=getSrc(e);

    //Anular efeito drag quando a janela está maximizada, ou caso o clique ocorra em locais indevidos
    if (this.telacheia && !this.minimizada) { return false; }
    if (this.minimizada) return this.restore();

    tE=this.wReference;
    evXY=getEventXY(e); this.locks={x: evXY['x'] -tE.offsetLeft, y: evXY['y'] -tE.offsetTop};
    adEvento(document, 'mousemove', this.moveWin.bindAsEventListener(this) );
    adEvento(document, 'mouseup', this.stopDrag.bindAsEventListener(this) );
    this.createDraggerArea('moving');
    return true;
  },
  moveWin: function(e, lastMove) { var tE, evXY=getEventXY(e), nPX, nPY; //alert('acionado');
    //Se a moldura não existir, e não for chamado pelo método "stopDrag" (indicado pelo parâmetro "lastMove")
    //criar a moldura que será arrastada, e colocar a janela em questão com a classe "arrastando"
    if (!this.moldura && !lastMove) {
      with (this) { wReference.className=addTok(wReference.className, 'arrastando', ' '); }
      this.moldura=this.createFrame.apply(this);
    }
    //Se for chamado pelo método "stopDrag", mover a janela real, ao invés da moldura
    tE=(lastMove) ? this.wReference : this.moldura;
    nPX=evXY['x'] -this.locks['x']; nPY=evXY['y'] -this.locks['y'];

    // Posicionamento mínimo da janela -- ao soltar, implementar limites de posicionamento
    if (lastMove) { if (!this.moldura) { return false; alert(this.moldura); }
      if (this.wReference.offsetLeft == nPX && this.wReference.offsetTop==nPY) return true;
      tE.style.visibility='hidden';
      //Coletar informações -- tamanho da janela JS e da janela do navegador
      var tW=tE.offsetWidth, tH=tE.offsetHeight, tBW=0, tBH=0;
      if (window.innerWidth) { tBW=window.innerWidth; tBH=window.innerHeight; }
      else if (document.documentElement && document.documentElement.clientWidth) {
        tBW=document.documentElement.clientWidth; tBH=document.documentElement.clientHeight;
      }
      else if (document.body) { tBW=document.body.clientWidth; tBH=document.body.clientHeight; }
      else { return false; }

      //Limites esquerdo e direito -- sobram no mínimo 90px
      if ((tW +nPX) < 90) { nPX=(-tW +90); } if (nPX > (tBW -90)) { nPX=(tBW -90); }
      //Limite superior e inferior -- a barra sempre fica totalmente visível
      if (nPY< -1) { nPY=(-1); } if (nPY > (tBH -30)) { nPY=(tBH -30); }
    }
    tE.style.left=nPX +'px'; tE.style.top=nPY +'px'; tE.style.visibility='visible';
  },
  stopDrag: function(e) { var tE; tE=this.wReference;
    //A remoção da classe acontece antes do chamado da movimentação, para evitar problemas de desempenho
    with (this) { wReference.className=remTok(wReference.className, 'arrastando', ' '); }
    this.moveWin.apply(this, [e, 1]);
    //Remover eventos no document -- parar a movimentação
    remEventos(document, ['mousemove', 'mouseup'] );
    //Remover camada de bloqueio e moldura
    this.removeDraggerAndFrame(); this.moldura=null;

    //Detectar doubleclick -- no caso de maximizado, não há a necessidade de "emular" o evento, pois ele realmente ocorrerá
    if (!this.telacheia) { var evXY=getEventXY(e);
      if (evXY['x'] == this.lastClickCoord['x'] && evXY['y'] == this.lastClickCoord['y'] &&
        (new Date().getTime() -this.lastClickTime) < 400) this.maximize.apply(this);
      this.lastClickCoord=evXY; this.lastClickTime=new Date().getTime();
    }

    return true;
  },

  /* ## Métodos para redimensionar */
  startResize: function(e) { this.getFocus(); e=(e||event); if ((e.which || e.button) != 1) return false;
    var tE, tAxis, evXY; tE=this.wReference; evXY=getEventXY(e);
    tAxis=getSrc(e).className.substr(getSrc(e).className.length -1, 1);

    this.resizing['x']=(tAxis == 'x' || tAxis == 'z'); this.resizing['y']=(tAxis == 'y' || tAxis == 'z');
    this.locks={x: tE.offsetWidth -evXY['x'] +tE.offsetLeft, y: tE.offsetHeight -evXY['y'] +tE.offsetTop };
    adEvento(document, 'mousemove', this.doResize.bindAsEventListener(this) );
    adEvento(document, 'mouseup', this.stopResize.bindAsEventListener(this) );
    this.createDraggerArea('resizing'+ tAxis);
  },
  doResize: function(e, lastResize) { var tE, evXY=getEventXY(e), nSX, nSY;
    //Se a moldura não existir, e não for chamado pelo método "stopResize" (indicado pelo parâmetro "lastResize")
    //criar a moldura que será arrastada, e colocar a janela em questão com a classe "redimensionando"
    if (!this.moldura && !lastResize) {
      with (this) { wReference.className=addTok(wReference.className, 'redimensionando', ' '); }
      this.moldura=this.createFrame.apply(this);
    }
    //Se for chamado pelo método "stopResize", redimensionar a janela real, ao invés da moldura
    tE=(lastResize) ? this.wReference : this.moldura;
    if (this.resizing['x']) { nSX=evXY['x'] -tE.offsetLeft +this.locks['x']; }
    if (this.resizing['y']) { nSY=tE.style.height=evXY['y'] -tE.offsetTop +this.locks['y']; }
    if (nSX) tE.style.width=((nSX > 150) ? nSX : 150) +'px';
    if (nSY) tE.style.height=((nSY > 150) ? nSY : 150) +'px';
    if (lastResize) { this.fReference.style.width='100%'; }
    return true;
  },
  stopResize: function(e) { remEventos(document, ['mousemove', 'mouseup'] );
    if (!this.moldura) return false; var tE; tE=this.wReference; this.doResize.apply(this, [e, 1]);
    with (this) { wReference.className=remTok(wReference.className, 'redimensionando', ' '); }
    this.adjustIFrameHeight.apply(this);
    //Remover camada de bloqueio e moldura
    this.removeDraggerAndFrame(); this.moldura=null;

    return true;
  },


  /* ## Métodos auxiliares dos botões */
  unminimize: function() { if (this.minimizada) { this.realocateMinimizedWindows.apply(this); }
    with (this) { wReference.className=remTok(wReference.className, 'minimizada', ' '); minimizada=0;
      wReference.style.bottom='auto'; this.realocateMinimizedWindows.apply(this);
    }
  },
  unmaximize: function(keepProp) {
    with (this) {
      wReference.className=remTok(wReference.className, 'telacheia', ' ');
      if (!keepProp) { telacheia=0; } wReference.style.bottom='auto';
    }
  },

  /* ## Métodos correspondentes à ações de botões */
  minimize: function() {
    /* Se já estiver minimizada, apenas restaurar */ if (this.minimizada) { return this.restore(); }
    /* Calcular posição vertical da janela minimizada */ var newBottomPosition=this.getNMinWindows() *winDigTitleBarHeight -1;
    with (this) {
      // Se maximizado, remover class da telacheia, mas manter propriedade indicativa no objeto
      if (telacheia) this.unmaximize.apply(this, [1]);
      // Adicionar minimização e propriedade
      wReference.className=addTok(wReference.className, 'minimizada', ' ');
      minimizada=1; wReference.style.bottom=newBottomPosition +'px';
    }
  },
  maximize: function() { /* Tomar foco */ this.getFocus.apply(this);
    /* Evitar eventos sequenciais -- */ var dt=new Date(); if (!this.redimensionavel || (dt.getTime() -this.maximizedTime) < 100) { return false; }
    /* Se já maximizada, apenas restaurar -- */ if (this.telacheia && !this.minimizada) { return this.restore.apply(this); }
    /* Armazenar tempo da maximização, pra evitar acionamento duplo -- */ this.maximizedTime=dt.getTime();
    /* Remover qualquer "minimização" existente -- */ this.unminimize.apply(this);
    //Aplicar a maximização à janela
    this.fReference.style.width='100%';
    this.wReference.className=addTok(this.wReference.className, 'telacheia', ' ');
    this.telacheia=1; this.wReference.style.bottom='auto';
    /* Ajustar altura do iFrame conteúdo -- */ this.adjustIFrameHeight.apply(this);
    return true;
  },
  restore: function() {
    with (this) {
      /* Se minimizada, mas em "tela cheia" */ if (telacheia && minimizada) { telacheia=0; return maximize.apply(this); }
      /* Em qualquer outro caso, remover m(in|ax)imização */
      if (telacheia || minimizada) { unminimize.apply(this); unmaximize.apply(this); adjustIFrameHeight.apply(this); }
    }
    return true;
  },


  /* ## Outros Métodos */
  //Atualização do conteúdo da janela
  reload: function() { this.fReference.contentWindow.document.location.reload(); },
  setTitle: function(newTitle, htmlTitle) { if (!newTitle) return false;
    var tTitleBar=this.wReference.firstChild.firstChild; rEs(tTitleBar.childNodes);
    if (htmlTitle) { tTitleBar.innerHTML=newTitle; } else { tTitleBar.appendChild(cTN(newTitle)); }
  },
  //Tomada de foco (colocar a janela a frente das demais)
  getFocus: function() { this.wReference.style.zIndex=++curWinDigZ; },
  //Ajuste da posição das janelas minimizadas
  realocateMinimizedWindows: function() { var minBottomToMove, n, cWB, tWins=gE('windigs').childNodes;
    minBottomToMove=this.wReference.style.bottom.replace(/^(-?[0-9]+).*/, '$1');
    for (n=tWins.length; n--; ) { if (hasTok(tWins[n].className, 'minimizada', ' ')) {
      cWB=Number(tWins[n].style.bottom.replace(/^([0-9]+).*/, '$1'));
      if (cWB > minBottomToMove) { tWins[n].style.bottom=cWB -winDigTitleBarHeight +'px'; }
      }
    }
  },


  /* ## Método Destrutor */
  close: function() { var tE=this.wReference; rEs(tE); this.realocateMinimizedWindows.apply(this);
    delete(windigs[this.tName]); try { delete(this); } catch(e) {  }
  }
};


/* ## Funções auxiliares */
//Recupera quantidade de pixels que a janela foi rolada
function getScrollPos() { var ret=Array();
  if (window.pageYOffset) { ret['x']=window.pageXOffset; ret['y']=window.pageYOffset; } //all except Explorer
  else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
	  ret['x']=document.documentElement.scrollLeft; ret['y']=document.documentElement.scrollTop; }
  else if (document.body) { ret['x']=document.body.scrollLeft; ret['y']=document.body.scrollTop; } //all other Explorers
  return ret;
}
//Cria "comporter" pr'as janelas, caso ainda não exista
function createWinDigsComporter() {
  if (!gE('windigs')) { gFETN('body')[0].appendChild(cE('div', 'id=windigs', '')); }
}
// Ajustar altura dos IFrames nas janelas maximizadas, em caso de redimensionamento da "janela-mãe"
function adjustIFrameHeights() { var tWins=gE('windigs').childNodes, n=tWins.length, i=0;
  for (;i<n;i++)
    if (hasTok(tWins[i].className, 'telacheia', ' ') && !hasTok(tWins[i].className, 'minimizada', ' '))
      tWins[i]._this.adjustIFrameHeight.apply(tWins[i]._this);
} //adEvento(window, 'resize', adjustIFrameHeights);
// Retornar a posição X/Y da ocorrência de um evento
function getEventXY(e) { return {x: (e.pageX ? e.pageX : e.clientX), y: (e.pageY ? e.pageY : e.clientY) }; }

// Retorna um valor booleano, indicando se a janela está aberta.
function winDigExists(tName) {
  return (windigs[tName] && windigs[tName].wReference && windigs[tName].wReference.parentNode);
}
// Retorna a janela com foco (a mais alta, na verdade)
function getFocusedWindow() {
  var n, tFW=0, tWins=gE('windigs').childNodes;
  for (n=tWins.length; n--; ) { if (tWins[n]._this.minimizada) { continue; }
    if (!tFW || tFW.style.zIndex < tWins[n].style.zIndex) { tFW=tWins[n]; }
  } return (tFW) ? tFW._this : 0;
}
// Fechar janela passando o nome dado inicialmente, na criação da janela
function closeWinDig(tName) { if (winDigExists(tName)) windigs[tName].close(); }

// Capturar tecla pressionada e executar ações devidas
function teclaPressionada(e) { var tecla=getKeyCode(e);
  /* Esc */ if (tecla == 27) { var tFW; if (tFW=getFocusedWindow()) { tFW.close(); } }
}


// Atribuir eventos e fazer alterações iniciais
function startWinDigEvents() {
  // Criar "comporter" das janelas, caso ainda não exista
  createWinDigsComporter();

  // Capturar teclas -- DESABILITADO NESSA VERSÃO
  //adEvento(document, 'keydown', teclaPressionada);

  // Tornar não-selecionável
  adEvento(document.body, 'selectstart', poin); adEvento(document.body, 'dragstart', poin);
} 
  //adEvento(window, 'load', startWinDigEvents);