jQuery(document).ready(function () {
  var $ = jQuery;
  var lib = fff;
  // general for loop
  try {
    // for testing:
    //
    //  $('#db-intro').css('display','none');
    //  $('#db-news').css('display','none');

    var track = function (url) {
      lib.track(url);
    }
    // save often used variables
    var closeSpeed = 400;
    var openSpeed = 800;
    var ie6 = lib.ie6;
    var ie7 = ($.browser.msie && ($.browser.version.substring(0,1)=='7'));
    var slideInEnabled = !ie6;
    var useAdGallery = ie6;
    var ipad = lib.ipad;
    var animateMarginLeft = ie6 || ie7;

    var handlingLocalLink = false;
    var nextLocalLink = '';

    var $html = $('html');
    var $ml = $('#ml');
    var $moodbild = $('#moodbild');
    var mood = $moodbild.attr('data-mood');
    var mbH = $moodbild.attr('data-default-height');
    var mbW = $moodbild.attr('data-default-width');
    var $moodSmall = $('#moodbild a');

    // ########## cm ###############
    var $cm = $('#cm');
    var $cmClose = $('#cm-close');
    var $mbg = $('#mbg');
    var $cmImg = $('#mbg img');
    var $moodDesc = $('#mood-desc');
    var moodDescOpacity = 0.8;
    var mbSize = 'default';
    var cmLeftBorder = 9;
    var cmRightBorder = 9;

    // ########## cu ################
    var cuWidth = 600;
    var $cu = $('#cu');
    var $cuPreload = $('#cu-preload');
    var $cuWrapper = $('#cu-wrapper');
    var $cuHide = $('#cu-hide');
    var $cuClose = $('#cu-close');

    // ########### db ###########
    var $dbWrapper = $('#db-wrapper');
    var $db = $('#db');
    var $dbUpper = $('#db #db-upper');
    var $ip = $('#ip');
    var $ipImg = $('#ip img');
    var ipSize;
    var $moodimage = $('#mbg img');
    var dbBorderLeft = 1;

    // ############ ip #############
    var useXLmbg = 800;
    var useXXLmbg = 1200;
    var useXLip = 1280;
    var useXXLip = 1920;
    var ipWidth;
    var ipHeight;
    var ipFadeInSpeed = 4000;

    //  console.log($ip.css('position'));
    //  alert($.browser + ' '+$.browser.version + ' ' + ie7);
    function getCmMinWidth () {
      return cmLeftBorder;
    }

    var setMlHeight = function () {};
    if (ipad) {
      setMlHeight = function (height) {
        $ml.height(height);
      };
    }

    // sets the height of the parents of cu explicitly
    var setCuParentsHeight = function () {
      var h = $cu.outerHeight(true);
      $cuHide.height(h);
      $cuWrapper.height(h);
    }

    function animationRunning() {
      var res = $dbWrapper.is(':animated');
      return res;
    }
  

    function dbFixed() {
      var ov = $dbWrapper.css('overflow');
      //    console.log('overflow:'+ov);
      return ov == 'hidden';
    }
    // to be called at window.resize() in ie6
    // fixes the layout to work with ie6
    function iefix() {
      var h = $(window).height();
      var w = $(window).width();
      $ml.height(h);
      $cm.height(h);
      $moodimage.attr('height', h);
      var imgw = $moodimage.width();
      var closew = $cmClose.width();
      var closel = imgw - (closew / 2);
      //console.log(closel);
      $cmClose.css('left',closel);
      var cuW=$cu.width();
      if (cuW) {
        // the cu is visible
        $db.css('left',900);
      }
    }

    $(window).scroll(function () {
      var top = $(window).scrollTop();
      if (ie6) {
        // move the elements which shall look like position:fixed
        $ml.css('top',top);
        $cm.css('top',top);
      }
    })

    // places the ip element at the bottom of the div#db.
    var placeip = function (evenIfFixed) {
      if (dbFixed()) {
        if (!evenIfFixed) {
          return;
        }
      }

      if (ie6)
      {
        return;
      }
      // get dimensions without scrollbars
      $('body').css('overflow','hidden');
      var h = $(window).height();
      var w = $(window).width();
      var upperH = $dbUpper.outerHeight();
      $('body').css('overflow','auto');

      // compute image dimensions
      var imgW = w - 309;
      // TODO replace with real computation, the aspect ratio may be different
      var imgH = Math.round(imgW / 5);
      //    console.log('window h:'+h+' w:'+w);

      var diff = h-(upperH+imgH);
      if (diff > 0) {
        // the window is high enough to allow a gap above the ip,
        if (dbFixed()) {
          // only reached if we start up with db fixed for the first setup
          //$db.height($('body').height());
          $ip.css({
            position : 'absolute',
            bottom : 0,
            top : 'auto',
            left : 0,
            right : 'auto'
          });
          $ip.css({
            width : '100%'
          });
        } else {
          //  we take the ip of the usual flow by making it position fixed
          $ip.css({
            position : 'fixed',
            bottom : 0,
            right : 0,
            top : 'auto',
            left : 'auto'
          });
          // apply img dimensions
          $ip.css({
            width : imgW,
            height :imgH
          });

          // now take care that the db is 100% high, to make shure the background expands to the
          // bottom
          $dbWrapper.height('100%');
          $db.height('100%');
        }
      } else {
        // diff < 0
        // the ip shall be in the normal document flow and have a 100% width
        $ip.css({
          position : 'static'
        });
        $ip.css({
          width: '100%',
          height : 'auto'
        });
        // set them to auto again, as 100% will be to short
        $dbWrapper.height('auto');
        $db.height('auto');
      }
    };

    // called after content has been loaded to the #cu
    var setUpGallery = function setUpGallery() {
      if (useAdGallery) {
        //      var n = $('#cu .ad-gallery').length;
        //      var n2 = $('.ad-gallery').length;
        //      console.log('setting up '+n+' ad-galleries. Total: '+n2);
        $('#cu .ad-gallery').adGallery({
          loader_image: '/share/ad-gallery/loader.gif',
          slideshow : {
            enable : false
          }
        });
        $('#cu .ad-gallery').css({
          visibility:'visible'
        });

      } else {
        // use galleria
        $('#cu .ad-gallery').galleria().css({
          visibility:'visible'
        });
      }
    }
    // to be called during document.ready event
    function initPage() {
      handleBlogImages();
      lib.initForm();
      setTimeout(setUpGallery, 1000)
      var w = $(window).width();
      var h = $(window).height();
      var mlW =$ml.width();
      if (isDbHidden()) {
        //      console.log('mlw:'+mlW+' w:'+w);
        var spaceForDb = w-mlW-getCmMinWidth();
        $db.width(spaceForDb-dbBorderLeft);
        $dbWrapper.css({
          position:'fixed'
        });
        if (isContent()) {
          var cuW = cuWidth;
          $dbWrapper.css({
            'margin-left' : mlW+cuW+getCmMinWidth()

          });
          // maybe this is just needed for ie6
          if (fff.ie6) {
            $dbWrapper.css('width',w-(mlW+cuW));
          }
          setMlHeight($cu.outerHeight(true));
        }
        if (isMood()) {
          // TODO do this on document.ready
          var cmImgW = getCmImgWidth(h);
          $mbg.width(cmImgW + cmRightBorder);
          $dbWrapper.css('margin-left',mlW+cmImgW+getCmMinWidth());
          if (fff.ie6) {
            $('#db-wrapper').css('width',w-(mlW+cmImgW+getCmMinWidth()));
          }
        }
      } else {
        // db not hidden
        // for ipad
        setMlHeight($db.outerHeight(true));
      // db not hidden
      }
      placeip(true);
      if (ie6) {
        // somehow this fixes the ie6 bug with the cu coming in from the right the first time
        $cuWrapper.animate({
          width:1
        },10);
      }
    }

    // moves the blog images to the beginning of the page and
    // creates the structure needed for ad-gallery
    function handleBlogImages() {
      var $p = $('#cu .gallery-placeholder');
      if (!$p) {
        // this means, this is not a blog page
        return;
      }
      var imgs = $('#cu .blog-post img');
      if (imgs.length < 1) {
        // we make a gallery only if there are more than 2 pics
        return;
      }
      if (imgs.length < 2) {
        // we have exactly 1 image
        var i = $(imgs[0]);
        $p.append(i);
        i.wrap('<div class="bildrahmen"></div>');
        return;
      }
      // construct the parts needed for the ad gallery
      var adgal = $('<div class="ad-gallery"></div>');
      adgal.append('<div class="ad-image-wrapper"></div><div class="ad-controls"></div>');
      var ul = $('<ul class="ad-thumb-list"></ul>');
      imgs.each(function () {
        var i = $(this)
        ul.append(i);
        i.wrap('<li><a href="#"></a></li>');
        i.parent('a').attr('href',i.attr('src'));
        i.removeAttr('height');
        i.removeAttr('width');
        i.removeAttr('title');
        i.removeAttr('alt');
      });
      adgal.append(ul);
      ul.wrap('<div class="ad-nav"><div class="ad-thumbs"></div></div>');
      $p.append(adgal);
    }
  
    // #################### afterContentLoad ################
    var afterContentLoad  = function afterContentLoad(cb) {
      Cufon.refresh();
      //handleBlogImages();
      //setUpGallery();
      lib.handleBlogImages(function () {
        lib.info('set up gallery');
        setUpGallery();
        lib.initForm();
        if (cb) {
          cb();
        }
      });
    }



    // ##################### the window.resize() function
    var resize = function () {
      var w = $(window).width();
      var h = $(window).height();
      if (ie6) {
        iefix();
      } else {
        checkMbSize(h);
        checkIpImgSize(w);
        placeip();
      }
      if (isMood()) {
        $mbg.width(getCmImgWidth(h)+cmRightBorder);
      }
    }

    $(window).resize(resize)

    if (ie6)
    {
      iefix();
    }

    var isMood = function () {
      var x = $cmClose.is(':visible');
      return x;
    }

    var isContent = function () {
      return $cuClose.is(':visible');
    }

    var isDbHidden = function () {
      return (isMood() || isContent());
    }

    if (ie6) {
      // as ie6 does not understand the double-class selector .js.db-hidden
      // these may be hidden
      $dbWrapper.css('display','block');
      $db.css('display','block');
    }

    // #######################################################
    // hijack all clicks
    // ##################################
    $(document).bind('click',function (e) {
      //    console.log(e.button);
      if (e.button !== 0)
      {
        return true;
      }
      if (animationRunning()) {
        // we just don't handle a click if an animation (on db-wrapper) is running
        console.log('click not handled, because animation running');
        return true;
      }
      // if the click was not on an <a> tag, we use the nearest parent <a>
      var target = $(e.target);
      var a;
      if (target.is('a')) {
        a = target;
      }
      var parentA = target.parents('a');
      if (parentA.length) {
        a = parentA.eq(0);
      }
      if (a) {
        if (handleLink(a)) {
          // if the framework already handled the link, we suppress the browser default action
          e.preventDefault();
          return false;
        }
      }
    // now handle clicks which are not on links
    });

    // checks if the link is a local link
    // this must begin with /
    // if the given href begins with the protocol and our own domain, these are stripped of,
    // so that we always get back only the local link
    var getlocallink = function (href) {
      if (!href) return undefined;
      // matches everything beginning with /
      if (href.match(/^\/(.*)?$/)) {
        return href;
      }
      var start = window.location.protocol + '//' + window.location.host;
      var r = href.indexOf(start);
      if (r < 0) {
        return undefined;
      }
      href = href.slice(r+start.length);
      return href;
    }


    var getCmImgDimensions = function () {
      return {
        'w':mbW,
        'h':mbH
      };
    }

    var getCmImgWidth = function (height) {
      var dim = getCmImgDimensions();
      return Math.floor(dim.w * height / dim.h)-1;
    }

  
    /**
   * Computes the cm image width for the given window size.
   */
    var getCmWidth = function () {
      var h = $(window).height();
      return getCmImgWidth(h) + cmRightBorder;
    }

    var moveDbToMargin;
    if (ie6) {
      moveDbToMargin = function (margin, speed) {
        // freeze db width
        $db.css({
          width : $db.width()
        });
        // height 100% makes the scrollbars dissapear if mood is shown
        $dbWrapper.css({
          overflow : 'hidden',
          height : '100%'
        });
        // animate the db
        $dbWrapper.animate(
        {
          marginLeft : margin,
          opacity : 0.3
        },speed);
      };
    } else {
      // not ie6
      moveDbToMargin = function (margin, speed) {
        // freeze db width
        $db.css({
          width : $db.width()
        });
        $dbWrapper.css({
          position : 'fixed',
          overflow : 'hidden',
          height : '100%'
        });
        // the ip img might be postion fixed
        // in this case we have to put it inside the dashboard to move it
        var pos = $ip.css('position');
        if (pos == 'fixed'){
          // this means the window is higher than the db
          $db.height($('body').height());
          $ip.css({
            position : 'absolute',
            bottom : 0,
            top : 'auto',
            left : 0,
            right : 'auto'
          });
        }
        // animate the db
        $dbWrapper.animate(
        {
          marginLeft : margin,
          opacity : 0.3
        },speed);
      };
    }

    /**
   * Brings to db back into a visible and usable position
   */
    var releaseDb = function (speed) {
      speed = speed || closeSpeed;
      // define callback
      var cb = function () {
        $db.css({
          width : 'auto',
          height : 'auto'
        });
        $dbWrapper.css({
          position : 'static',
          overflow : 'auto',
          height: 'auto'
        });
        placeip();
        // for ipad:
        setMlHeight($dbWrapper.outerHeight(true));
        $html.removeClass('db-hidden');
        $dbWrapper.unbind('click');
      }
      $dbWrapper.animate(
      {
        marginLeft : $ml.width() + cmLeftBorder -dbBorderLeft, // -1 for 1 pixel border at dbWrapper
        opacity : 1
      },speed,'swing',cb);
    }

    function setDbHidden() {
      // set the css marker
      $html.addClass('db-hidden');
      // catch clicks on the db overlay
      $dbWrapper.click(function (ev) {
        ev.preventDefault();
        return false;
      });
    }
    function scrolltoTop () {
      console.log('scrollToTop');
      $(window).scrollTop(0);
      if (ie6) {
        iefix();
        $ml.css('top',0);
        $cm.css('top',0);
      }
    }
    /**
   * Opens the content mood
   */
    function openCm(callback) {
      if (ie6) {
        scrolltoTop()
      }
      var speed = openSpeed;
      // do preparation
      setDbHidden();
      var cmWidth = getCmWidth();
      if (fff.ie6) {
        $cmImg.css({
          width : cmWidth
        });
      }
      $cmImg.height('100%');
      $cm.css({
        width : 'auto',
        zIndex : 2000
      });
      var ml = cmWidth + $ml.width();
      $moodDesc.css({
        opacity: 0,
        display: 'block'
      });

      // define callback
      var cb = function () {
        $cmClose.fadeIn(closeSpeed);
        $moodDesc.animate({
          opacity: moodDescOpacity
        },openSpeed);
        $moodSmall.attr('href', '/');

        if (ie6) {
          var dbw = $(window).width() - $ml.width() - cmWidth;
          // we have to set the wrapper width explicitly
          $dbWrapper.width(dbw);
        }
        if (callback) {
          callback();
        }
      }

      // run animation
      moveDbToMargin(ml,speed);

      if (animateMarginLeft) {
        $cmImg.css('margin-left',-cmWidth);
        $cmImg.animate({
          marginLeft:0
        }, speed);
      }
      $cmImg.width('auto');
      $mbg.animate({
        width: cmWidth
      },speed,'swing',cb);
    }

    var closeCm = function (callback) {
      var speed = closeSpeed;
      // hide the close button
      $cmClose.css({
        display: 'none'
      });
      $moodDesc.css({
        display : 'none'
      });

      if (ie6) {
        // we have to always set this on ie6
        $dbWrapper.width('auto');
        // simulate float
        // TODO this for ie7, too?
        $cmImg.animate({
          marginLeft : -$cm.width()
        }, speed, 'swing', function () {});
      }

      // define callback
      var cb = function () {
        // executed after animation
        $cmImg.width(0); // necessary for safari, otherwise it will still overlap db
        $db.css({
          width : 'auto'
        });
        $dbWrapper.css({
          overflow : 'auto'
        });
        $moodSmall.attr('href', '/mood.html');
        if (callback) {
          callback();
        }
      }

      // run animation
      releaseDb();
      $mbg.animate(
      {
        width: 0
      },
      speed,'swing',cb)
    }

    function openCu (callback) {
      if (ie6) {
        scrolltoTop()
      }
      var speed = openSpeed;
      //    speed = 4000;
      setDbHidden();
      // set wrapper and hide div to cu height
      $cuHide.css('display','block');
      var cuH = $cu.outerHeight(true);
      // set the height of the cu-wrapper and the cu-hide explicitly
      $cuWrapper.css({
        height : cuH
      });
      $cuHide.css({
        height : cuH,
        overflow : 'hidden',
        width : 'auto'
      });

      // compute margin-left for db
      var margin = $ml.width()+getCmMinWidth()+ cuWidth;
      //    console.log('margin'+margin);

      // define callback
      var cb = function () {
        $cuWrapper.css({
          height: 'auto'
        });
        $cuHide.css({
          height: 'auto',
          overflow: 'visible'
        });
        // set the ml height to the cu height for ipad
        setMlHeight($cu.outerHeight(true));
        $cuClose.fadeIn(closeSpeed);
        if (callback) {
          callback();
        }
      };

      // run animation
      moveDbToMargin(margin,speed);
      $cuWrapper.animate({ // sets overflow:hidden for cu-wrapper
        width : cuWidth
      }, speed);
      $cuHide.animate({
        width : cuWidth
      }, speed,'swing',cb);

    }

    var closeCu = function closeCu(callback) {
      var speed = closeSpeed;
      // hide the close button
      $cuClose.css('display','none');
      // do preparation
      $cuWrapper.css({
        height : $cu.height()
      });
      $cuHide.css({
        height : $cu.height(),
        overflow : 'hidden'
      });
      // define callback
      var cb = function () {
        $cuWrapper.css({
          height : 'auto'
        });
        $cuHide.css({
          display : 'none',
          height : 'auto'
        });

        // we reset the title to the default title, but save the current title
        var title = document.title;
        $cu.attr('data-title',title);
        document.title = lib.defaultTitle;
        if (callback) {
          callback();
        }
      };

      // run animation
      releaseDb();
      $cuWrapper.animate({ // sets overflow:hidden for cu-wrapper
        width : 0
      }, speed);
      $cuHide.animate({
        width : 0
      }, speed,'swing',cb);
    }

    function slidein(cont,newcont,contwidth,direction,style,cb) {
      var speed = 1000;
      // set default directon from right
      if (direction !== 'fromleft') {
        direction = 'fromright';
      }
      // save content positioning values
      var contPos = cont.css('position');
      var contLeft = cont.css('left');
      var contRight = cont.css('right');
      // wrap content in div
      cont.wrap('<div id = "wrapper" style="position:relative;"/>');
      var $wrap = cont.parent();
      //    $wrap.width(contwidth * 2);

      // save parent scrollbar css
      var $parent = $wrap.parent();
      var position = $parent.css('position');
      var overflow = $parent.css('overflow');
      var overflowx = $parent.css('overflow-x');
      var overflowy = $parent.css('overflow-y');
      // hide parent scrollbars

      $parent.css({
        position : 'relative',
        overflow : 'hidden',
        overflowX : 'hidden',
        overflowY : 'hidden'
      });
      if (position == 'static') {
        // necessary to avoid a ie bug, where hidden stuff is still visible
        $parent.css({
          position: 'relative'
        })
      }
      //$wrap.parent().css('overflow', 'auto');
      var $oldcont;
      // define the callback function when the slide is over
      var slideready = function() {
        // remove old content
        $oldcont.remove();
        // restore parent scrollbar settings
        $wrap.parent().css({
          position : position,
          overflow : overflow,
          overflowX : overflowx,
          overflowY : overflowy
        });
        // remove wrapper
        cont.unwrap();
        // reset content position css
        cont.css({
          position: contPos,
          left : contLeft,
          right : contRight
        });
        $cuHide.height('auto');
        $cuWrapper.height('auto');
        if (cb) {
          cb();
        }
        // scroll to top of screen, as the current scroll postition might be useless now
        $('html, body').scrollable().animate({
          scrollTop: 0
        }, 400);
      }

      if (direction === 'fromright') {
        // add the div for the old content at the left
        cont.before('<div style="float: left"/>');
        $oldcont = cont.prev();
        // copy the old content to the new div
        $oldcont.html(cont.html());
        // write the new content into the new div
        cont.html(newcont.html());
        // move content to the right
        cont.css({
          position: 'absolute',
          left : contwidth,
          top : 0
        });
        // there may be javascript to be applied to the new markup
        style();
        // and slide back in
        $wrap.animate({
          left : -contwidth
        },
        speed,
        'easeOutQuad',
        slideready);
      } else {
        console.log('parent overflow '+$parent.css('overflow'));
        // slide in from left
        // add the div for the old content at the right
        cont.after('<div style="float: right"/>');
        $oldcont = cont.next();
        // copy the current content to oldcont and the new to cont
        $oldcont.html(cont.html());
        cont.html(newcont.html());
        style();
        // move the new content to the left
        cont.css({
          position: 'absolute',
          left : -contwidth,
          top : 0
        });
        //      $wrap.css({
        //        left : '0px'
        //      });
        // and slide back in to the right
        $wrap.animate({
          left : contwidth
        },
        speed,
        'easeOutQuad',
        slideready);

      }
    }


    function loadContent(param, successcallback, cancelcallback) {
      var dataParam = $('body').attr('data-path');
      if (dataParam == param) {
        console.log('loadContent cancelled because content already loaded');
        // but we have to restore the title
        var title = $cu.attr('data-title');
        if (title) {
          document.title = title;
        }
        if (cancelcallback) {
          cancelcallback();
        }
        return;
      } else {
        console.log('now loading content:'+param);
      }
      // now load the content via ajax
      var successHandler =function(html) {
        // Each content page should start with a special comment (see: docs/readme.txt)
        // We extract the metainfo in this comment here
        //        console.log('ajax success');
        var re=/^\s*<!--([\s\S]*?)-->/;
        var a = re.exec(html);
        if (a) {
          var meta = a[1]
          // In javascript, the dot never matches newlines, so we get the rest of the line,
          // where the line started with withespace - tit - more letters or whitespace - :
          var titleA = /[\s\r\n]*tit(?:[\w\s]*)?:(.*)/.exec(meta);
          //            var descA = /[\s\r\n]*des(?:[\w\s]*)?:(.*)/.exec(meta);
          //            var keywA = /[\s\r\n]*key(?:[\w\s]*)?:(.*)/.exec(meta);
          if (titleA) {
            var title = titleA[1];
            document.title = title;
          }
          // At this time, there is no need to deal with the description
          // and meta-tags information here
          //            if (descA) {
          //              var desc = descA[1];
          //              console.log(desc);
          //            }
          //            if (keywA) {
          //              var keyw = keywA[1];
          //              console.log(keyw);
          //            }
          // remove the meta-info comment from the string
          html = html.replace(re,'');
        }
        else {
          console.log('missing metadata for content: '+param);
        }
        // save to data-path
        $('body').attr('data-path', param);
        if (successcallback) {
          // give back the result in the callback
          successcallback(html);
        }
      }

      var errorHandler =function (request, status, error) {
        console.log('ajax error');
        loadContent('error.html');
        if (successcallback) {
          successcallback();
        }
      }
    
      $.ajax({
        dataType: 'html',
        url: '/ajax'+param,
        success: successHandler,
        error: errorHandler
      });
    }

    var handleLocalLink = function handleLocalLink(localLink) {
      lib.info('handleLocalLink: '+localLink);
      if (handlingLocalLink) {
        // we are already handling a link, so lets save the link to be handled later
        lib.info('handleLocalLink cancelled, saving link: '+localLink);
        nextLocalLink = localLink;
        return;
      }
      lib.info('handling started');
      handlingLocalLink = true;
      var linkHandled = function () {
        lib.info('handling finished');
        handlingLocalLink = false;
        if (nextLocalLink) {
          var link = nextLocalLink;
          nextLocalLink = '';
          handleLocalLink(link);
        }
      }
      // Handle mood link
      if (localLink == "/mood.html") {
        // The user wants to open the cm
        if (isMood()) {
          // the cm is already visible: do nothing
          linkHandled();
        } else {
          // the cm is not yet visible
          if (isContent()){
            // we have to close the content area first
            closeCu(function () {
              openCm(linkHandled);
            })
          } else {
            // no cu
            openCm(linkHandled);
          }
        }
      }
      // handle link back to start page
      else if (localLink == "/"){
        if (isMood()) {
          closeCm(linkHandled);
        } else  if (isContent()){
          // not cm
          closeCu(linkHandled);
        } else {
          // nothing is open, so we are done
          linkHandled();
        }
      }

      else {
        // it is a path to content
        if (isMood()) {
          // the cm is open: we close it and open cu
          closeCm(function () {
            var success = function (html) {
              $cu.html(html);
              afterContentLoad(function () {
                openCu(linkHandled);
              });
            }
            var cancel = function () {
              // loading has been cancelled because the content is already laoded
              openCu(linkHandled);
            }
            // give the callback as successcallback and cancelcallback
            loadContent(localLink,success,cancel);
          });
        } else {
          // cm not open
          //define callback
          var success = function (html) {
            // open the cu only if it is not visible already
            if (!isContent()) {
              // the cu is not visible yet
              $cu.html(html);
              afterContentLoad();
              openCu(linkHandled);
            } else {
              // the cu is visible, we save the content to the preload div and slide it in

              if (slideInEnabled) {
                $cuPreload.html(html);
                // determine direction
                var indexold = $cu.find('.cu-un').attr('data-index');
                var indexnew = $cuPreload.find('.cu-un').attr('data-index');
                //              console.log('old index: '+indexold + ' new: '+ indexnew);
                var direction =  (indexnew < indexold)?"fromleft":"fromright";
                slidein($cu,$cuPreload,cuWidth,direction,afterContentLoad, linkHandled);
              }
              else {
                // slide in not enabled, just exchange the content
                $cu.html(html);
                afterContentLoad();
                linkHandled();
              }
            }
          }
          var cancel = function () {
            // loading was cancelled, so there is no html
            if (!isContent()) {
              // cu not visible
              openCu(linkHandled);
            } else {
              // cu visible, nothing really to do here
              linkHandled();
            }
          }
          loadContent(localLink,success,cancel);
        }
      
      }
    }

    $.fn.ffhistory.init(handleLocalLink,track);
    // if there is nothing after #, it uses '/', no matter what is in the real url
  
    // ################### handleLink ##########################
    // The central 'link-hijacking' function.
    // Tries to do something with the link via ajax.
    // #########################################################
    function handleLink(link) {
      var href = link.attr('href');
      var localLink = getlocallink(href);
      if (localLink) {
        $.fn.ffhistory.historyLoad(localLink);
        // true means: link is handled
        // we assume that we can handle each local link
        return true;
      }
      return false;
    }



    var getMbSize = function (height) {
      if (height > useXXLmbg) {
        return 'xxl'
      }
      if (height > useXLmbg) {
        return 'xl';
      }
      return 'default';
    }

    var getIpSize = function (width) {
      if (width > useXXLip) {
        return 'xxl';
      }
      if (width > useXLip) {
        return 'xl';
      }
      return 'default';
    }

    var isMbTooSmall = function (correctSize) {

      if (correctSize == 'default') return false;
      if (correctSize == 'xl') {
        if (mbSize == 'default') {
          return true;
        } else {
          return false
        }
      }
      if (correctSize == 'xxl') {
        if (mbSize == 'xxl') {
          return false
        } else {
          return true;
        }
      }
      console.log('invalid size argument:'+correctSize);
    }

    var isIpTooSmall = function (correctSize) {
      if (correctSize == 'default') return false;
      if (correctSize == 'xl') {
        if (ipSize == 'default') {
          return true;
        } else {
          return false;
        }
      }
      if (correctSize == 'xxl') {
        if (ipSize == 'xxl') {
          return false;
        } else {
          return true;
        }
      }
      console.log('invalid size argument:'+correctSize);
    }

    var getMoodImgData = function (size) {
      if (!size) {
        alert ('no size attribute for getModdImgData');
      }
      var src;
      var $e = $moodbild;
      src = $e.attr('data-'+size+'-file');
      mbW = $e.attr('data-'+size+'-width');
      mbH = $e.attr('data-'+size+'-height');
      return src;
    }
    // returns the correct src attribute for the current window width
    // and sets ipWidth and ipHeight as a side effect
    var getIpImgData = function (size) {
      var src = $ip.attr('data-'+size+'-file');
      ipWidth = $ip.attr('data-'+size+'-width');
      ipHeight = $ip.attr('data-'+size+'-height');
      return src;
    }

    // checks if the current mb is
    var checkMbSize = function (height) {
      var size = getMbSize(height);
      //    console.log('correct size for h:'+height+' :'+size);
      if (isMbTooSmall(size)) {
        //      console.log('reloading mb with size:'+size);
        mbSize = size;
        var src = getMoodImgData(size);
        replaceMoodImg(src);
      } else {
    //      console.log('not reloading mb');
    }
    }


    // loads a new ip image from the given src
    var loadIpImg = function loadIpImg(src) {
      //    console.log('ip img src:'+src);
      var panorama = $ip.attr('data-panorama');
      var path = '/share/hazards/panorama/'+panorama+'/'+src;
      //console.log('src:'+path);
      var loadHandler = function () {
        // we check if there is an ip image already
        var oldImg = $ip.find('img');
        if (!oldImg.length) {
          // the image is not there
          // first, we remove this handler
          // to avoid recalling it accidentally
          img.unbind('load',loadHandler);
          // at this time we can load the high res cm image:
          checkMbSize($(window).height());
          //        console.log('adding new ip image');
          $ip.append(img);
          // is this needed:?
          //        placeip(true);
          // fade it in
          img.css('opacity',0);
          img.animate({
            opacity : 1
          },ipFadeInSpeed,'swing',function () {
            // needed for ie: otherwise the filter makes the edge look strange
            img.removeAttr('style');
          });
        } else {
          // just reloading
          //          console.log('img already found, just setting path:'+path);
          // prevent a loop:
          oldImg.attr('src', path);
        }
      }
      var img = $('<img />').attr('src',path);
      img.load(loadHandler);
    }

    var checkIpImgSize = function (width) {
      var size = getIpSize(width);
      if (isIpTooSmall(size)) {
        ipSize = size;
        console.log('reloading ip with size: '+size);
        var src= getIpImgData(size);
        loadIpImg(src);
      } else {
        console.log('ip is not to small with size '+ipSize + ' for width '+width);
      }
    }

  

    // replaces the mood img with the one with the given src
    var replaceMoodImg = function (src) {
      if (!src) {
        alert ('no src');
      }
      var path = '/share/hazards/moods/'+mood+'/'+src;
      //    console.log('moodbild path:'+path);
      var loadHandler = function () {
        // now prevent the image from changing its size
        // setting the src to the path gets the loaded image from the cache
        $cmImg.attr('src',path);
        $cmImg.width('auto');
        if (isMood()) {
          $mbg.width(getCmImgWidth() + cmRightBorder);
        }
      //      console.log('mb reloaded');
      }
      // we just load the image to an unattached img element
      // this puts it into the browser cache
      var img = $('<img />').attr('src',path).load(loadHandler);
    }
  
    $(window).load(function () {
      // executed one time after everything is loaded, including images

      // move db to the right
      if (!ie6) {
        var w = $(window).width();
        var size = getIpSize(w);
        ipSize = size;
        var src = getIpImgData(size);
        loadIpImg(src, true);
      }
    });

    $(document).keyup(function(e){
      //      console.log('keyup:'+e.keyCode);
      if (e.keyCode === 27)
      {
        // esc pressed
        if (isContent()) {
          $.fn.ffhistory.historyLoad('/');
        }
        if (isMood()) {
          $.fn.ffhistory.historyLoad('/');
        }
      }
    });
  
    initPage();


  } catch (e) {
    lib.handle(e);
  }
}); // end of document.ready()
// things to be executed immediately:

