function nano_$(root, element) {
  if (typeof element == 'string')
    element = root.document.getElementById(element);
  return Element.extend(element);
}

function nano_remove_element(element) {
  element.parentNode.removeChild(element)
}
function nano_close_dialog(root1, root2) {
  nano_remove_element(root1.document.getElementById('dialog'));
  nano_remove_element(root1.document.getElementById('dialog-box'));
  if (root2) {
    nano_remove_element(root2.document.getElementById('dialog'));
    nano_remove_element(root2.document.getElementById('dialog-box'));
  }
}

/* this doesn not deal with evaluating inserted scripts */
Element.frameUpdate = function(root, element, html) {
  Element.setFrameStyle(root, element, {display: 'none'});
  nano_$(root, element).innerHTML = html;
  return element;
/*  nano_$(root, element).innerHTML = html.stripScripts();
  setTimeout(function() {html.evalScripts()}, 10);
  return element;*/
}

Element.getFrameDimensions = function(root, element) {
  element = nano_$(root, element);
  if (Element.getStyle(element, 'display') != 'none')
    return {width: element.offsetWidth, height: element.offsetHeight};

  // All *Width and *Height properties give 0 on elements with display none,
  // so enable the element temporarily
  var els = element.style;
  var originalVisibility = els.visibility;
  var originalPosition = els.position;
  els.visibility = 'hidden';
  els.position = 'absolute';
  els.display = '';
  var originalWidth = element.clientWidth;
  var originalHeight = element.clientHeight;
  els.display = 'none';
  els.position = originalPosition;
  els.visibility = originalVisibility;
  return {width: originalWidth, height: originalHeight};
}

Element.setFrameStyle = function(root, element, style) {
  element = nano_$(root, element);
  for (var name in style) {
/*    alert("setFrameStyle%"+name+"%"+style[name]+"%");*/
    element.style[name.camelize()] = style[name];
  }
  return element;
}

Element.setFrameOpacity = function(root, element, value) {
  Element.setFrameStyle(root, element, {opacity: value});
  if(/MSIE/.test(navigator.userAgent) && !window.opera) {
    Element.setFrameStyle(root, element, { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + 'alpha(opacity='+value*100+')' });
  }
}

// Returns array with x,y page scroll values.
// Core code from - quirksmode.org
Position.getFramePageScroll = function(root) {
  if(self.pageYOffset)
    return self.pageYOffset;
  if(root.document.documentElement && root.document.documentElement.scrollTop) // Explorer 6 Strict
    return root.document.documentElement.scrollTop;
  if(root.document.body) // all other Explorers
    return root.document.body.scrollTop;
}

// Returns array with page width, height and window width, height
// Core code from - quirksmode.org
// Edit for Firefox by pHaez
Position.getFramePageSize = function(root) {
  var xScroll, yScroll;

  if (root.window.innerHeight && root.window.scrollMaxY) {  
    xScroll = root.document.body.scrollWidth;
    yScroll = root.window.innerHeight + root.window.scrollMaxY;
  } else if (root.document.body.scrollHeight > root.document.body.offsetHeight){ // all but Explorer Mac
    xScroll = root.document.body.scrollWidth;
    yScroll = root.document.body.scrollHeight;
  } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
    xScroll = root.document.body.offsetWidth;
    yScroll = root.document.body.offsetHeight;
  }

  var windowWidth, windowHeight;
  if (root.innerHeight) { // all except Explorer
    windowWidth = root.innerWidth;
    windowHeight = root.innerHeight;
  } else if (root.document.documentElement && root.document.documentElement.clientHeight) { // Explorer 6 Strict Mode
    windowWidth = root.document.documentElement.clientWidth;
    windowHeight = root.document.documentElement.clientHeight;
  } else if (root.document.body) { // other Explorers
    windowWidth = root.document.body.clientWidth;
    windowHeight = root.document.body.clientHeight;
  } 

  // for small pages with total height less then height of the viewport
  pageHeight = Math.max(windowHeight, yScroll);

  // for small pages with total width less then width of the viewport
  pageWidth = Math.max(windowWidth, xScroll);

  return { page: { width: pageWidth, height: pageHeight }, window: { width: windowWidth, height: windowHeight } };
}

var FrameDialog = {
  clearObservers: function(root) {
    if (!FrameDialog.resizeObserver) return;    
    Event.stopObserving(root.window, 'resize', FrameDialog.resizeObserver);
    Event.stopObserving(root.window, 'scroll', FrameDialog.resizeObserver);
    FrameDialog.resizeObserver = null;
    FrameDialog.current        = null;
  },

  close: function() {
    this.onCallback('onClose');
    this.clearObservers(window); /*Is this the right root at runtime?*/
    ['dialog', 'dialog-box'].each(function(d) { if($(d)) Element.remove(d); });
  },

  onCallback: function(callback) {
    if(FrameDialog.current.options[callback]) FrameDialog.current.options[callback]();
  },
  
  Base: Class.create()
};

FrameDialog.Base.prototype = {
  defaultOptions: {},

  initialize: function(root, loading, options) {
    this.options = Object.extend(Object.extend({}, this.defaultOptions), options);
    this.loading = loading;
    this.create(root);
  },

  setupDialog: function(root) {
    this.createDialogElements(root);
    this.setContents();
  },

  setContents: function() {
    // this.dialogBox.innerHTML = ....
  },

  createDialogElements: function(root) {
    this.dialog    = root.document.createElement('div');
    this.dialogBox = root.document.createElement('div');
    this.dialog.setAttribute('id', 'dialog');
    this.dialogBox.setAttribute('id', 'dialog-box');
    Element.setFrameStyle(root, this.dialog,    {zIndex: 100, backgroundColor: '#000'});
    Element.setFrameStyle(root, this.dialogBox, {zIndex: 101, display:'none'});
  },

  create: function(root) {
    this.setupDialog(root);
    root.document.body.appendChild(this.dialog);
    root.document.body.appendChild(this.dialogBox);
    this.afterCreate(root);
  },
  
  afterCreate: function(root) {
    this.root = root;
    this.layout(root);
    FrameDialog.resizeObserver = this.layout.bind(this);
    Event.observe(root.window, 'resize', FrameDialog.resizeObserver);
    Event.observe(root.window, 'scroll', FrameDialog.resizeObserver);

/*    new Effect.Fade(this.dialog, {from: 0.1, to: 0.4, duration:0.15});
    new Effect.Appear(this.dialogBox, {duration:0.4});*/
    Element.setFrameOpacity(root, this.dialog, 0.5)
    Element.setFrameStyle(root, this.dialogBox, {display: 'block'})
    
    FrameDialog.current = this;
  },

  layout: function(root) {
    var pg_dimensions = Position.getFramePageSize(this.root);
    var el_dimensions = Element.getFrameDimensions(this.root, 'dialog-box');
    var scrollY       = Position.getFramePageScroll(this.root);
    
    Element.setFrameStyle(this.root, 'dialog', {
      position:'absolute', top:0, left:0,
      width: pg_dimensions.page.width  + 'px',
      height:pg_dimensions.page.height + 'px'
    });

    Element.setFrameStyle(this.root, 'dialog-box', {
      position:'absolute',
      top:  ((pg_dimensions.window.height - el_dimensions.height) / 2) + scrollY + 'px',
      left: ((pg_dimensions.window.width - el_dimensions.width)  / 2) + 'px'
    })
    Element.setFrameStyle(this.root, 'dialog-box', {display: 'block'});
  },

  close: function() {
/*    new Effect.Fade('dialog-box', {duration: 0.2, afterFinish: function() { FrameDialog.close(); }});*/
    FrameDialog.close();
  }
};

FrameDialog.Rjs = Class.create();
Object.extend(Object.extend(FrameDialog.Rjs.prototype, FrameDialog.Base.prototype), {
  defaultOptions: Object.extend(Object.extend({}, FrameDialog.Base.prototype.defaultOptions), {}),
  setContents: function() {
    if (this.loading) {
      this.dialogBox.innerHTML = '<div style="background-color: #fff; border-width: 1px; border-color: #000; border-style: double; padding: 10px 10px;font-family: Arial Narrow, Arial, Helvetica, sans-serif; font-size: 14px;"><p>Loading... Please wait.</p><p><a href="#" onclick="parent.nav.nano_close_dialog(window, parent.nav); return false;">close</a></div>';
    }
  }
});