/* from scripts/constants.js */
var INTRO_IMAGE_WIDTH=1280;
var INTRO_IMAGE_HEIGHT=1024;
var CONTENT_WIDTH=970;  // must be the same as in main.css!
var CONTENT_HEIGHT=578;

var PROJECT_IDS = [];
$.each(PROJECTS, function() { PROJECT_IDS.push(this.id); });


/* from scripts/helpers.js */
// eases val [0..1] -> [0..1]
var ease = function(val) {
  return ((-Math.cos(val*Math.PI)/2) + 0.5);
};

Precalc = (function() {
  var fns = [];
  var running = false;
  var timeout = false;
  var timeoutCallback = null;
  var counter = 0;

  var log = function() {
    $("#log").html("len: " + fns.length + ", running: " + running + ", counter: " + (counter++));
  }

  var process = function() {
    if (!running) return;
    log();
    var now = (new Date()).getTime();
    if (timeout && now > timeout) {
      running = timeout = false;
      if (typeof timeoutCallback == "function") timeoutCallback();
      return;
    }
    if (fns.length > 0) {
      fns[0].fn();
      fns.splice(0, 1);
      setTimeout(process, 0);
    } else {
      if (timeout) {
        var diff = timeout - now;
        running = timeout = false;
        if (typeof timeoutCallback == "function") setTimeout(timeoutCallback, diff);
      } else {
        running = false;
      }
      log();
    }
  };

  return {
    start: function() {
      timeout = false;
      running = true;
      process();
    },
    stop: function() {
      running = false;
      log();
    },
    add: function(cat, fn) {
      fns.push({ cat:cat, fn:fn });
      log();
    },
    wait: function(fn, millisecs) {
      running = true;
      timeoutCallback = fn;
      timeout = (new Date()).getTime() + millisecs;
      process();
    },
    processCategory: function(cat) {
      for (var i=0; i<fns.length; ++i) {
        if (fns[i].cat == cat) {
          fns[i].fn();
          fns.splice(i, 1);
          --i;
        }
        log();
      }
    }
  };
})();

$(window).load(function() {
  var onResize = function() {
    var $b = $("body");
    $b.css({ width: $(window).width() < CONTENT_WIDTH ? CONTENT_WIDTH + "px" : "100%"});
    $b.css({ height: $(window).height() < CONTENT_HEIGHT ? CONTENT_HEIGHT + "px" : "100%"});
    $('.intro-image').backgroundResize();
  };
  $(window).resize(function() {
    onResize();
    setTimeout(onResize, 300);  // resize again due to scrollbar changes
  });
  onResize();
});

// Our jQuery image resize extension
jQuery.fn.extend({
  backgroundResize: function() {
    var $wrapper = this.parent();
    var bw = $('body').width();
    var bh = $('body').height();
    if (bw < CONTENT_WIDTH) bw = CONTENT_WIDTH;
    if (bh < CONTENT_HEIGHT) bh = CONTENT_HEIGHT;
    $wrapper.css({ width:bw, height:bh })

    var iw = bh / INTRO_IMAGE_HEIGHT * INTRO_IMAGE_WIDTH;
    var ih = bw / INTRO_IMAGE_WIDTH * INTRO_IMAGE_HEIGHT;

    if (ih > bh) {
      this.css({ width:bw + "px", height:ih + "px",
          top:((bh-ih)/2) + "px", left:0 });
    } else {
      this.css({ width:iw + "px", height:bh + "px",
          top:0, left:((bw-iw)/2) + "px" });
    }
  }
});


/* from scripts/main.js */
if ($.browser.msie) {
  try { document.execCommand("BackgroundImageCache", false, true); } catch(e) {}
//document.execCommand("BackgroundImageCache", false, true);
}

var initialFunction = null;

var History = (function() {
  var currentDestination = null;

  jssm.settings.blankurl = 'scripts/jssm-iframe.html';
  jssm.functions.load = function(hash) {
    var fn = functionForHash(hash);
    if (fn) {
      fn()
    } else {
      var href = window.location.href;
      if (/#/.exec(href)) href = href.substring(0, href.indexOf("#") - 1);
      window.location = href;
    }
  };
  jssm.functions.pageload = function(hash) {
    initialFunction = functionForHash(hash);
  };

  var functionForHash = function(hash) {
    var res = /^([^\/]+)/.exec(hash);
    if (res) {
      var dest = res[1];
      if (dest == "current") dest = currentDestination || "default";
      var table = Table.forDestination(dest);
      if (currentDestination == dest && table) {
        return function() {
          // perform the table animation
          table.animateTo(table.parseHash(hash));
        }
      }
      currentDestination = dest;
      if (!table) return null;
      return function() {
        table.renderCoord(table.parseHash(hash), true); // renderMasterTable
      };
    } else {
      // no destination - start normal
      return null;
    }
  }
  return {
    setHash: function(hash) {
      jssm.setHash(hash);
    },
    setCurrentDestination: function(dest) {
      currentDestination = dest;
    }
  }
})();

Shadowbox.loadSkin("classic", "fileadmin/scripts/shadowbox-skin");
Shadowbox.loadLanguage("de-DE", "fileadmin/scripts");
Shadowbox.loadPlayer(["img", "iframe"], "fileadmin/scripts");

$(function() {
  Table.addPrecalc();
  $("#scene-table").css({ display:"block", left:"-200%" });
  Precalc.start();
});

$(window).load(function() {
  Precalc.stop();
  Shadowbox.init();
  (initialFunction || Start.start)();
});




/* from scripts/scene1-start.js */
var Start = (function() {
  return {
    start: function() {
      var introStarted = false;
      var swooshStarted = false;
//      Table.start();
//      return;
      $("#next-scene-link").css({ display:"block" }).click(function() {
        Precalc.stop();
        $("#scene-start").fadeOut();
        $("#please-wait").css({ display:"block" });
        $(this).hide();
        if (introStarted) {
          Intro.stop();  // when finished this will execute Swoosh.start
        } else {
          swooshStarted = true;
          Swoosh.start();
        }
        return false;
      });
      $('#content').css({ display:"block" });
      // $('#scene-start').css({ display:"block", opacity:0 }).animate({ opacity:1 }, 3000);
      setTimeout(function() {
        if (swooshStarted) return;
        introStarted = true;
        Intro.start();
      }, 1);
    }
  };
})();

/* from scripts/scene2-intro.js */


var Intro = (function() {
  var running = false;  // is the intro running?
  var gone = false;     // are we gone to the next scene?
  var fadeRunning = false;
  var currentProjectId = "";

  var loadImage = function(projectId, callback) {
    var index = $.inArray(projectId, PROJECT_IDS);
    var project = PROJECTS[index];
    var src = project.introImage;
    // var src = project.introImage || "fileadmin/images/" + projectId + "-bg.jpg";
    var image = new Image();
    image.onabort = image.onerror = image.onload = function() {
      if (nextScene()) return;
      var wrapperSelector = "#scene-intro-" + projectId + " .intro-image-wrapper";
      $(wrapperSelector).html(
        '<img src="' + src + '" class="intro-image"/>');
      setTimeout(function() {
        $(wrapperSelector +  " .intro-image").backgroundResize();
      }, 200);
      if (typeof callback == "function") callback();
    };
    image.src = src;
  };

  var nextScene = function() {
    if (!running && !gone) {
      gone = true;
      Swoosh.start(currentProjectId);
    }
    return !running;
  }

  var fade = function(from, to) {
    fadeRunning = true
    var $from = $(from);
    var $to = $(to);
    $from.css({ display:"block", opacity:1, zIndex:100 });
    $from.find("*").css({ zIndex:100 });
    $to.css({ display:"block", opacity:1, zIndex:99 });
    $to.find("*").css({ zIndex:99 });
    $to.find(".intro-image").backgroundResize();
    $from.fadeOut(2000, function() {
      fadeRunning = false;
      $from.hide();
      if (nextScene()) return;
      next();
    });
    return;
  }

  var next = function() {
    if (nextScene()) return;
    var index = $.inArray(currentProjectId, PROJECT_IDS) + 1;
    if (index >= PROJECT_IDS.length) {
      $("#next-scene-link").hide();
      $("#please-wait").css({ display:"block" });
      Table.setInitialProjectId(PROJECT_IDS[0]);
      Intro.stop();
      return;
    } //index = 0;
    var nextSceneId = PROJECT_IDS[index];
    var start = (new Date()).getTime();

    loadImage(nextSceneId, function() {
      if (nextScene()) return;
      var remaining = 5000 - ((new Date()).getTime() - start);
      if (remaining < 0) remaining = 0;
      Precalc.wait(function() {
        if (nextScene()) return;
        fade("#scene-intro-" + currentProjectId, "#scene-intro-" +  nextSceneId);
        currentProjectId = nextSceneId;
      }, remaining);
    });
  };

  return {
    start: function() {
      running = true; gone = false;
      currentProjectId = PROJECT_IDS[0];
      loadImage(currentProjectId, function() {
        fade("#scene-start", "#scene-intro-" + currentProjectId);
      });
    },
    stop: function() {
      running = false;
      if (!fadeRunning) {
        nextScene();
      }
    }
  };
})();


/* from scripts/scene3-swoosh.js */

var Swoosh = (function() {
  var visibleProjectId = null;
  
  var swooshProjects = function() {
    if (visibleProjectId) {
      $("#scene-intro-" + visibleProjectId).css({ zIndex:99 })
          .find(".content").css({ display:"none" });
      $("#scene-intro-" + visibleProjectId + " *").css({ zIndex:99 });
    }
    var waitTime = 0;
    $.each(PROJECT_IDS, function() {
      var projectId = this;
      if (projectId != visibleProjectId) {
        $("#scene-swoosh .project-" + projectId).css({
            left: Math.round((Math.random()*5-6) * 1000) + "px" }).find("p").hide();

        setTimeout(function() {
          if (projectId != visibleProjectId) {
            $("#scene-swoosh .project-" + projectId).animate({ left:"20px"}, 2000);
          }
        }, waitTime);
      }
      waitTime += 300;
    });
    setTimeout(verticalBars, 3000);
  };

  var verticalBars = function() {
    var $vertical = $("#scene-swoosh .vertical");
    var height = CONTENT_HEIGHT - 20 ;
    $vertical.html("");
    for (var i=0; i<10; ++i) {
      (function() {  // we need a closure here
        var line = $('<div class="line"> </div>');
        line.css({
          left: (i*28 + 210) + "px",
          top: Math.round((Math.random()*5 - 6) * 1000) + "px",
          height: height +  "px"
        });
        $vertical.append(line);
        var callback = null;
        if (i == 9) {
          callback = function() {
            setTimeout(function() {
              Table.start(visibleProjectId);
            }, 1000); 
          };
        }
        setTimeout(function() {
          line.animate({ top:"20px" }, 2000, callback);
        }, i * 300);
      })();
    }
  };

  return {
    start: function(projectId) {
      visibleProjectId = projectId;
      $("#scene-swoosh").css({ display:"block", zIndex:100 });
      $("#scene-swoosh").find("p").css({ zIndex:101 });
      running = true; gone = false;
      $("#scene-swoosh .project").css({ left: "-4000px" });
      if (visibleProjectId) {
        var project = $("#scene-swoosh .project-" + visibleProjectId);
        project.css({ left: "20px" });
        project.find("p").fadeOut(4000);
        setTimeout(function() {
          $("#scene-intro-" + visibleProjectId).fadeOut(2000);
        }, 3000);
      } else {
        $("#scene-start").fadeOut(3000);
      }
      swooshProjects();
    }
  };
})();


/* from scripts/scene4-table.js */
var Table = (function() {
  var EL_HEIGHT = 304;
  var EL_WIDTH = 450;

  var STEPS = 10;
  var currentElement = null;
  var initialProjectId = null;

  var td = function(c, opts) {
    opts = opts || {};
    var a = [];
    a.push("<div class=\"td");
    if (opts.klass) a.push(" " + opts.klass);
    a.push("\"");
    if (opts.style) a.push(" style=\"" + opts.style + "\"");
    a.push(">" + (c || "&nbsp;"));
    a.push("</div>");
    return a.join("");
  };

  var showVita = function(cur) {
    var imgSrc = $(cur.el).attr("href");
    var vitaText = $(cur.el).find(".vita-text").html();
    if (!vitaText || vitaText == "") return;
    var poll = function() {
      var $inner = $('#shadowbox_body_inner');
      if ($inner.get(0)) {
        var $img = $inner.find("img");
        if ($img && $img.get(0) && $img.attr("src").match(imgSrc + "$")) {
          $inner.append('<div class="vita-box"><span>' + vitaText + '</span></div>');
          return;
        }
      }
      setTimeout(poll, 100);
    };
    poll();
  };

  var DefaultTable = {
    name: "default-table",
    destination: "default",
    domAnimationsId: function() { return "#" + this.name + "-animations"; },
    render: function(id) {
      var a = [];
      a.push('<table');
      if (id) a.push(' id="' + id + '"');
      a.push(' class="default" cellpadding="0" cellspacing="0" style="left:-200%; position:absolute;"><tbody>');
      a.push('<tr class="head"><td class="nav"><div><a href="#" class="rotate"><span>Rotieren</span></a></div></td>');
      $.each(PROJECT_TOPICS, function() {
        a.push('<td class="' + this.id + ' topic">' +
            td(this.name, { klass: "default-topic-" + this.id }) +
            "</td>");
      });
      a.push('<td class="tail"></td></tr>');
      $.each(PROJECTS, function() {
        var project = this;
        var backgroundStyle = "background-color: " + project.background + ";";
        a.push('<tr class="' + project.id + '">' +
            '<td class="' + project.id + ' project project-bg" style="' + backgroundStyle + '">' +
            td(project.name, { klass:'default-prj-name-' + project.id }) + '</td>');
        $.each(PROJECT_TOPICS, function() {
          a.push('<td class="', this.id, ' project-bg has-el" style="', backgroundStyle, '">',
              td(null, { klass: "el" }), '</td>');
        });
        a.push('<td class="tail project-bg" style="' + backgroundStyle + '"></td>');
        a.push("</tr>");
      });
      a.push('<tr class="foot"><td></td>');
      $.each(PROJECT_TOPICS, function() {
        a.push('<td></td>');
      });
      a.push('<td class="tail"></td></tr></tbody></table>');
      return a.join("");
    },
    renderMasterTable: function() {
      $("#table-container").html("");
      var div = document.createElement("div");
      div.innerHTML = this.render("master-table");
      //initMasterTable(true);
      document.getElementById("table-container").appendChild(div.childNodes[0]);
    },
    renderCoord: function(coord, renderMaster, previousCoord) {
	
//	  console.log("master?", renderMaster);
//	  console.log(new Date() + ' 1');
	  var previousElementSelector = null;
	  if (previousCoord) {
		previousElementSelector = selectorForCoord(previousCoord, true);
	  } else {
	    renderMaster = true;
	  }
      currentElement = coord;

      // reset widths, heights, etc.
      if (renderMaster) { this.renderMasterTable(); currentTable = this; }
      $("#scene-table").css({ left:0 });
//	  console.log(new Date() + ' 2');
	  //if (previousElement) $("#scene-table " + selectorForCoord(previousElement + " .el")).css({ width:"28px", height:"28px" });
      $("#master-table").find(".el").css({ width:"28px", height:"28px" });
      $(this.domAnimationsId() + " table").css({ left:"-200%"});
      $("#master-table " + selectorForCoord(coord)).css({width:EL_WIDTH + "px", height:EL_HEIGHT + "px" });
//	  console.log(new Date() + ' 3');
      initMasterTable(renderMaster);
      if (renderMaster) this.loadContent(coord);
//	  console.log(new Date() + ' 4');
	  if (previousElementSelector) {
		$("#master-table " + previousElementSelector).bind("click", elementClicked);
        $("#master-table " + previousElementSelector).css({ cursor:"pointer" });
  	  }
      $("#master-table " + selectorForCoord(coord, true)).unbind("click", elementClicked);
      $("#master-table " + selectorForCoord(coord, true)).css({ cursor:"auto" });
      enableKeypressEvents();
      Precalc.start();
      setTimeout(function() {
	    $("#scene-table").find(".el").css({ width:"28px", height:"28px" });
        $("#master-table " + selectorForCoord(coord)).css({width:EL_WIDTH + "px", height:EL_HEIGHT + "px" });
      }, 50);
//	  console.log(new Date() + ' 5');
    },
	loadContent: function(coord) {
	  if (!coord) return;
	  var sel = "#master-table " + selectorForCoord(coord);
	  var pos = this.getPos(coord);
	  $(sel).html('<div class="content"><div class="spinner">&nbsp;</div></div>');
	  //if ($(sel + " .content").html() != "") return;  // we already have data
	  $.ajax({
	    type: "GET",
	    url: (window.SCRIPT_URL || "index.php?type=999&id=") + PROJECTS[pos.projectPos].pages[pos.topicPos],
	    success: function(data) {
	      $(sel).html(data);
	      $(sel + " a.shadowbox").shadowbox({
	        onOpen:function(cur) { showVita(cur); disableKeypressEvents(); },
	        onClose:enableKeypressEvents,
	        onChange:function(cur) { showVita(cur); }
	      });
		  // Ajax  
	      // $(sel + " acronym").each(function() {
	      //   var $acr = $(this);
	      //   $acr.qtip({ 
	      //       content:$acr.attr("title"),
	      //       position: {
	      //         corner: { target:"bottomLeft", tooltip:"topRight" }
	      //       },
	      //       style: {
	      //         background: '#083151',
	      //         color: '#fff',
	      //         border: { width:0 },
	      //         classes: { content: "qtip-content" }
	      //       }
	      //   });
	      //   $acr.attr("title", null);
	      // });
	    },
	    error: function(data) {
	      $(sel).html('<div class="content">Ein Fehler ist aufgetreten.</div>');
	      // for testing shadowbox
	      //$(sel).html('<div class="content"><a href="/" class="shadowbox" rel="shadowbox;player=iframe">XXX</a></div>');
	      //$(sel + " a.shadowbox").shadowbox();
	    }
	  });
	},
    animate: function(from, to, callback) {
 	  // var start = new Date().getTime();

      Precalc.stop();
      disableKeypressEvents();
      var fromSel = selectorForCoord(from);
      var toSel = selectorForCoord(to);
      if (from) $(fromSel).html("");
      this.loadContent(to);

      for (var step=0; step <= STEPS; step++) {
        var anim = animation(step);
        anim.css({ position:"absolute", left:"-200%" });
        var w = Math.round(ease(step / STEPS) * (EL_WIDTH - 28));
        var h = Math.round(ease(step / STEPS) * (EL_HEIGHT - 28));
        if (from && to && from.topic == to.topic) {
          if (currentTable == DefaultTable) w = 0; else h = 0;
        }
        if (from && to && from.project == to.project) {
          if (currentTable == DefaultTable) h = 0; else w = 0;
        }
        if (from) {
          anim.find(fromSel).css({
            width: (EL_WIDTH - w) + "px",
            height: (EL_HEIGHT - h) + "px"
          });
        }
        if (to) {
          anim.find(toSel).css({
            width: (w + 28) + "px",
            height: (h + 28) + "px"
          });
        }
      }

      $('#master-table').css({ position:"absolute", left:"-200%" });
      step = 0;  // yep this is a local variable
      var table = this;
      var nextStep = function() {
        if (step > 0) animation(step - 1).css({ left:"-200%" });
        animation(step).css({ left:"0" });
        step++;
        if (step <= STEPS) {
          setTimeout(nextStep, 13);
        } else {
          setTimeout(function() {
            currentTable.renderCoord(to, false, from);
            currentTable.initTitleClicks();
            if (typeof callback == "function") callback();
            Precalc.start();
            //alert(new Date().getTime() - start);
			
          }, 20);
        }
      };
      nextStep();
    },
    animateTo: function(to, callback) {

      var oldCur = currentElement;
      currentElement = to;
      this.animate(oldCur, to, callback);
    },
    getPos: function(coord) {
      var ret = { projectPos: -1, topicPos: -1 };
      $.each(PROJECTS, function(index) {
        if (coord.project == this.id) ret.projectPos = index;
      });
      $.each(PROJECT_TOPICS, function(index) {
        if (coord.topic == this.id) ret.topicPos = index;
      });
      return ret;
    },
    currentPos: function() {
      return this.getPos(currentElement);
    },
    updatedCurrentPos: function(x, y) {
      var pos = this.currentPos();
      pos.topicPos += x;
      pos.projectPos += y;
      return pos;
    },
    selectRelative: function(x, y) {
      var pos = this.updatedCurrentPos(x, y);
      var topicPos = pos.topicPos;
      if (topicPos < 0) topicPos = 0;
      if (topicPos >= PROJECT_TOPICS.length) topicPos = PROJECT_TOPICS.length - 1;
      var projectPos = pos.projectPos;
      if (projectPos < 0) projectPos = 0;
      if (projectPos >= PROJECT_TOPICS.length) projectPos = PROJECT_TOPICS.length - 1;
      this.setHash({ project:PROJECTS[projectPos].id, topic:PROJECT_TOPICS[topicPos].id });
    },
    parseHash: function(hash) {
      var res = /^([^\/]+)\/([^\/]+)\/([^\/]+)$/.exec(hash);
      return res ? { project:res[2], topic:res[3] } : null;
    },
    setHash: function(coord) {
      History.setHash("default/" + (coord ? (coord.project + "/" + coord.topic) : ""));
    },
    elementClicked: function(elClass, trClass) {
      this.setHash({ project:trClass, topic:elClass });
    },
    topicClicked: function() {
      currentTable.setHash({ 
          project: currentElement ? currentElement.project : PROJECTS[0].id,
          topic: $(this).attr("class").match(/^[^ ]+/)[0]
        });
    },
    projectClicked: function() {
      currentTable.setHash({ 
          topic: currentElement ? currentElement.topic : PROJECT_TOPICS[0].id,
          project: $(this).attr("class").match(/^[^ ]+/)[0]
        });
    },
    initTitleClicks: function() {
      var self = this;
      $("#master-table td.topic").unbind("click", self.topicClicked).css({ cursor: "default" });
      $.each(PROJECT_TOPICS, function() {
        if (!currentElement || currentElement.topic != this.id) {
          $("#master-table td.topic." + this.id).click(self.topicClicked).css({ cursor: "pointer" });
        }
      });
      $("#master-table td.project").unbind("click", self.projectClicked).css({ cursor: "default" });
      $.each(PROJECTS, function() {
        if (!currentElement || currentElement.project != this.id) {
          $("#master-table td.project." + this.id).click(self.projectClicked).css({ cursor: "pointer" });
        }
      });
    }
  };

  var FlippedTable = $.extend({}, DefaultTable, {
    name: "flipped-table",
    destination: "flipped",
    render: function(id) {
      var a = [];
      a.push('<table');
      if (id) a.push(' id="' + id + '"');
      a.push(' class="flipped" cellpadding="0" cellspacing="0" style="left:-200%; position:absolute;"><tbody>');
      a.push('<tr class="head"><td class="nav"><div><a href="#" class="rotate"><span>Rotieren</span></a></div></td>');
      $.each(PROJECTS, function() {
        a.push('<td class="', this.id, ' project project-bg" style="',
            'background-color:', this.background, ';">',
            td(this.name, { klass: "flipped-prj-name-" + this.id }) + "</td>");
      });
      a.push('<td class="tail"></td></tr>');
      $.each(PROJECT_TOPICS, function() {
        var topic = this;
        a.push("<tr class=\"" + topic.id + "\">" +
            '<td class="' + topic.id + ' topic">' +
            td(topic.name, { klass:'flipped-topic-' + topic.id }) + "</td>");
        $.each(PROJECTS, function() {
          var backgroundStyle = "background-color:" + this.background + ";";
          a.push('<td class="', this.id, ' project-bg has-el" style="', backgroundStyle, '">',
              td(null, { klass: "el" }), '</td>');
        });
        a.push('<td class="tail"></td>');
        a.push("</tr>");
      });
      a.push('<tr class="foot"><td class="topic"></td>');
      $.each(PROJECTS, function() {
        var backgroundStyle = "background-color:" + this.background + ";";
        a.push('<td class="project-bg" style="'+ backgroundStyle + '">' +
              /* td(null, { klass: "el" }) + */'</td>');
      });
      a.push('<td class="tail"></td></tr></tbody></table>');
      return a.join("");
    },
    updatedCurrentPos: function(x, y) {
      var pos = this.currentPos();
      pos.topicPos += y;
      pos.projectPos += x;
      return pos;
    },
    setHash: function(coord) {
      History.setHash("flipped/" + (coord ? (coord.project + "/" + coord.topic) : ""));
    },
    parseHash: function(hash) {
      var res = /^([^\/]+)\/([^\/]+)\/([^\/]+)$/.exec(hash);
      return res ? { project:res[2], topic:res[3] } : null;
    },
    elementClicked: function(elClass, trClass) {
      this.setHash({ project:elClass, topic:trClass });
    }
  });
  
  var currentTable = DefaultTable;

  var initAnimationContainer = function(table) {
    var start = (new Date()).getTime();
    $(table.domAnimationsId()).html("");
    var frag = document.createDocumentFragment();
    var div = document.createElement('div');
    frag.appendChild(div);
    div.innerHTML = table.render();
    for (var step=0; step <= STEPS; step++) {
      /*
      var anim = $(defaultTable("anim" + step));
      anim.css({ position:"absolute", left:"-200%" });
      anim.appendTo('#animation-container');
      */
/*      var div = document.createElement("div");
      div.innerHTML = tableFunc();
      document.getElementById("animation-container").appendChild(div.childNodes[0]);
*/
      Precalc.add(table.name, function() {
        document.getElementById(table.domAnimationsId().substr(1)).appendChild(frag.cloneNode(true).childNodes[0].childNodes[0]);
      });

      //$("#animation-container").append(defaultTable("anim" + step));
    }
  };

  var selectorForCoord = function(coord, skipEl) {
    if (!coord) return null;
    var s = currentTable == DefaultTable ?
        "." + coord.project + " ." + coord.topic :
        "." + coord.topic + " ." + coord.project;
    return s + (skipEl ? "" :" .el");
  };

  var initMasterTable = function(renderMaster) {
    $("#master-table").css({ left:0 });
    if (renderMaster) {
      $("#master-table td.has-el").click(elementClicked);
	  $("#master-table td.has-el").css({ cursor:"pointer" });
	  $("#master-table td.nav .rotate").click(rotateClicked);
	  currentTable.initTitleClicks();
    }
  };

  var animation = function(step) {
    return $(currentTable.domAnimationsId()).children("table:eq(" + step + ")");
  };

  var switchTable = function() {
    currentTable = currentTable != DefaultTable ? DefaultTable : FlippedTable;
  };

  var elementClicked = function() {
    var myClass = $(this).attr("class").match(/^([^\s]+)/)[1];
    var trClass = $(this).parents("tr").attr("class").match(/^([^\s]+)/)[1];   
    currentTable.elementClicked(myClass, trClass);
  };

  var rotateClicked = function() {
    Precalc.stop();
    disableKeypressEvents();
    var saveCurrentElement = currentElement;
    currentTable.animateTo(null, function() {
      Precalc.processCategory("flipped-table");
      Precalc.processCategory("default-table");
      var firstCallback = true;
      $("#master-table .project .td, #master-table .topic .td, #master-table a.rotate").fadeOut(600, function() {
        $(this).css({ display:"block", visibility:"hidden" });
        if (!firstCallback) return;
        firstCallback = false;
        setTimeout(function() {
          $("#scene-table").css({ left:"-200%" });  // .hide() eats too much cpu on ie!
          $("#scene-rotate").show();
          Rotate.start(currentTable != DefaultTable, function() {
            switchTable();
            currentTable.renderMasterTable();
            $("#master-table").css({ left: 0 });
            $("#scene-rotate").hide();
            $("#scene-table").css({ left:0 });
            var firstCallback = true;
            $("#master-table .project .td, #master-table .topic .td, #master-table a.rotate").css({ display:"block" }).hide().fadeIn(600, function() {
              if (!firstCallback) return;
              firstCallback = false;
              History.setCurrentDestination(currentTable.destination);
              currentTable.setHash(saveCurrentElement); // also performs animation
            });
          });
        }, 50);
      });
    });
    return false;
  };

  var keypressEvent = function(e) {
    switch(e.keyCode) {
      case 37: // left
        currentTable.selectRelative(-1, 0);
        return false;
      case 38: // up
        currentTable.selectRelative(0, -1);
        return false;
      case 39: // right
        currentTable.selectRelative(1, 0);
        return false;
      case 40: // down
        currentTable.selectRelative(0, 1);
        return false;
    }
    return true;
  };

  var enableKeypressEvents = function() {
    $(document).keydown(keypressEvent);
  };

  var disableKeypressEvents = function() {
    $(document).unbind("keydown", keypressEvent);
  };

  return {
    addPrecalc: function() {
      initAnimationContainer(DefaultTable);
      initAnimationContainer(FlippedTable);
    },
    setInitialProjectId: function(projectId) {
      initialProjectId = projectId;
    },
    start: function(project) {
      if (initialProjectId) project = initialProjectId;
      $("#scene-swoosh").hide();
      $("#please-wait").hide();
      $("#scene-table").css({ left:0 });
      currentTable.renderMasterTable();
      $("#master-table").css({ left:0 });
      var firstCallback = true;
      $("#master-table .topic .td").css({ display:"block" }).hide().fadeIn(1000, function() {
        if (!firstCallback) return;
        firstCallback = false;

        setTimeout(function() {
          Precalc.processCategory("default-table");
          var coord = { project: (project || PROJECT_IDS[0]), topic:PROJECT_TOPICS[0].id };
          History.setCurrentDestination("default");
          currentTable.setHash(coord);
        }, 300);
      });
    },
    forDestination: function(dest) {
      switch(dest) {
        case DefaultTable.destination: return DefaultTable;
        case FlippedTable.destination: return FlippedTable;
      }
      return null;
    }
  };
})();


/* from scripts/scene5-rotate.js */
var Rotate = (function() {
  var canvas;
  var ctx;
  var DURATION = 1000;
  var WIDTH = 950;
  var HEIGHT = 544;
  var TOP = 190;
  var LEFT = 190;

  var drawProjects = function(width) {
    $.each(PROJECTS, function(i) {
      ctx.fillStyle = this.background;
      ctx.fillRect(0, TOP + i*28 - 1, width, 24);
    });
  };


  var drawVerticals = function(height) {
    var drawLine = $.browser.msie ?
      function(pos) {
        ctx.fillStyle = "#84B0D0";
        ctx.fillRect(LEFT + i * 28 - 1, 0, 1, height);
      } :
      function(pos) {
        ctx.drawImage($('#vertical-image').get(0), 0, 0, 1, height,
          LEFT + i*28 - 1, 0, 1, height);
      };
    for (var i=0; i<=PROJECT_TOPICS.length; ++i) drawLine(i);
  };

  var draw = function(pos) {
    var r = Math.PI/2 * pos;
    if (r > Math.PI/2) r = Math.PI/2;
    canvas.width = canvas.width;

    var w = WIDTH * (1 - pos) + HEIGHT * pos;
    var h = HEIGHT * (1 - pos) + WIDTH * pos;
/*
    // draw fix reference table
    ctx.save();
    ctx.translate(20, 20);
    drawProjects(WIDTH);
    drawVerticals(HEIGHT);
    ctx.restore();
*/
    ctx.save();
    ctx.translate(20 + LEFT, 20 + TOP);
    ctx.rotate(-r);
    ctx.translate((-HEIGHT + LEFT + TOP) * pos - LEFT, -TOP);
    drawProjects(w);
    ctx.restore();

    ctx.save();
    ctx.translate(20 + LEFT, 20 + TOP);
    ctx.rotate(r);
    ctx.translate(-LEFT, (-WIDTH + LEFT + TOP) * pos - TOP);
    drawVerticals(h);
    ctx.restore();
  };

  var animate = function(inverse, callback) {
    var r = 0;
    var start = (new Date()).getTime();
    var rot = function() {
      var diff = (new Date()).getTime() - start;
      if (diff > DURATION) diff = DURATION;
      var pos = ease(diff / DURATION);
      if (inverse) pos = 1-pos;
      draw(pos);
      if (diff < DURATION) {
        setTimeout(rot, 13);
      } else {
        if (typeof callback == "function") setTimeout(callback, 0);
      }
    };
    rot();
  };

  return {
    start: function(inverse, callback) {
      canvas = $('#rotate-canvas').get(0);
      if (window.G_vmlCanvasManager) {
        canvas = G_vmlCanvasManager.initElement(canvas);
      }
      ctx = canvas.getContext("2d");
      draw(inverse ? 1 : 0);
      animate(inverse, callback);
    }
  };
})();

