
function Loader(){
  this.show = function(){
    $("#loader").show();
  }
  this.hide = function(){
    $("#loader").hide();
  }
}
function HistoryApi(){
  var $this = this,
    isHTML5;

  this.hasHTML5Support = function(){
    if(isHTML5 !== undefined){
      return isHTML5;
    } else {
      return isHTML5 = !!(window.history && history.pushState);
    }
  }

  this.changeUrl = function(url){
    if(this.hasHTML5Support()){
      history.pushState({}, "", url);
    } else {
      $.address.value(url);
    }
  }

  this.registerOnChange = function(){
    if(this.hasHTML5Support()){
      window.onpopstate = function(event){
        loadUrl(document.location.pathname);
      }
    } else {
      var firstRun = true;
      $.address.change(function(event){
        var href = event.path;
        if($.address.baseURL()+"/" != homepage){
          document.location = homepage+"#"+document.location.pathname;
          return;
        }
        if(href == "/" && firstRun){
          // do not load anything - main page is always loaded first
          firstRun = false;
          return;
        }
        firstRun = false;

        loadUrl(href);
      });
    }
  }

  this.registerForms = function(){
    $("form.local").live("submit", function(event){
      event.preventDefault();
      var $form = $(this),
        invalid = false;
      $(".required", $form).each(function(){
        $this = $(this);
        if($this.val() == ""){
          highlightRequired($this);
          invalid = true;
        }
      });
      $('input.required[name^="hinter_"]', $form).each(function(){
        $this = $(this);
          highlightRequired($this);
          invalid = true;
      });
      if(invalid){
        return;
      }
      $.ajax({
        type: "post",
        dataType: "json",
        url: $form.attr("action"),
        data: $form.serialize(),
        success: function(data, textStatus, XMLHttpRequest){
          if(data.url != undefined){
            History.changeUrl(data.url);
            if(data.redirect != undefined){
              loadUrl(data.url);
              return;
            }
          }
          updatePage(data);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown){
          data = {};
          try {
            data = $.parseJSON(XMLHttpRequest.responseText);
          } catch(error){
            data.content = XMLHttpRequest.responseText;
          }
          updatePage(data);
        },
        beforeSend: function(XMLHttpRequest){
          Loader.show();
        },
        complete: function(XMLHttpRequest, textStatus){
          Loader.hide();
        }
      });
    });
  }

  this.registerClick = function(){
    if(this.hasHTML5Support()){
      $("a.local").live("click", function(event){
        event.preventDefault();
        href = $(this).attr("href");

        if(href != document.location.pathname){
          history.pushState({}, "", href);
        }
        loadUrl(href);
      });
    } else {
      $("a.local").address(function(){
        href = $(this).attr("href");
        if(href == $.address.value()){
          $.address.update();
        }
        else {
          return href.replace(homepage, "");
        }
      });
    }
  }

  this.initialize = function(){
    if(this.hasHTML5Support() && $.address.value() != "/"){
      document.location = $.address.value();
    }
    this.registerForms();
    this.registerOnChange();
    this.registerClick();
  }

  this.initialize();
}

var Cache = function(options){
  this.settings = $.extend({
    maxSize: 50,
    lifetime: 300
  }, options);
  var settings = this.settings;

  var data = {};
  var size = 0;

  // Creating our own shift function because associative keys in js sucks
  var shift = function(obj){
    for(i in obj){
      value = data[i];
      delete data[i];
      return value;
    }
  }

  this.add = function(key, value){
    // If cache is full, remove first value
    if(size >= settings.maxSize){
      shift(data);
      size--;
    } else if(!data[key]){
      size++;
    }
    // Add the value at the end of array
    return data[key] = {
      expiresAt: new Date().getTime() + (settings.lifetime * 1000),
      value: value
    }
  }

  this.get = function(key){
    if(data[key] && data[key].expiresAt < new Date().getTime()){
      // cache expired
      delete data[key];
      size--;
      return undefined;
    }

    return data[key];
  }
}









var Slider = function(){
  var object = this,
    timer,
    last,
    $images,
    $slider,
    $slideshow,
    $buttons,
    $buttonsContainer,
    lock = false,
    duration = 400; // "normal"
  this.manualChange = function(index){
    object.stop();
    changeSlide(index);
  };
  this.next = function(){
    changeSlide();
  };
  this.start = function(){
    timer = setTimeout(object.next, 4000);
  };
  this.stop = function(){
    clearTimeout(timer);
  };
  this.initialize = function(){
    object.stop();
    $slider = $("#slider");
    $slideshow = $("div.slider-slideshow", $slider);
    $images = $("img", $slideshow);
    $buttonsContainer = $("#slider-buttons");
    addButtons();
    $buttons = $("span", $buttonsContainer);
    $buttons.click(function(){
      $this = $(this);
      if($this.hasClass("active")){
        return;
      }
      object.manualChange($this.attr("index"));
    });
    $("img:not(.active)", $slideshow).each(function(){
      src = $(this).attr("src");
      $('<img />').attr("src", src);
    });
    if($images.length > 1){
      object.start();
      $("<div/>").attr("id", "slider-button-left").appendTo($slider).click(function(){
        object.manualChange("prev");
      });
      $("<div/>").attr("id", "slider-button-right").appendTo($slider).click(function(){
        object.manualChange();
      });
    }
  };
  function addButtons(){
    $images.each(function(index){
      $this = $(this);
      $span = $("<span/>").attr("index", index).css("opacity", 0.5);
      $buttonsContainer.append($span);
      last = index;
      if(index == 0){
        $this.addClass("active");
        $span.addClass("active");
      }
    });
  }
  var changeSlide = function(next){
    if(lock){
      return;
    }
    lock = true;
    if(next == undefined){
      next = $("img.active", $slideshow).index() + 1;
    } else if(next == "prev"){
      next = $("img.active", $slideshow).index() - 1;
    }
    if(next > last){
      next = 0;
    } else if(next < 0){
      next = last;
    }
    $("span.active", $buttonsContainer).removeClass("active");
    $("span[index="+next+"]", $buttonsContainer).addClass("active");
    $currentImg = $("img.active", $slideshow);
    $nextImg = $("img:eq("+next+")", $slideshow);
    if(next > $currentImg.index()){
      $nextImg.fadeIn(duration, function(){
        $currentImg.hide(0, function(){
          lock = false;
          object.start();
        }).removeClass("active");
      }).addClass("active");
    } else {
      $nextImg.show(0, function(){
        $currentImg.fadeOut(duration, function(){
          lock = false;
          object.start();
        }).removeClass("active");
      }).addClass("active");
    }
  }
}

var SliderHome = function(){
  var object = this,
    timer,
    $images,
    $slideshow,
    lock = false,
    duration = 400; // "normal"
  this.next = function(){
    changeSlide();
  };
  this.start = function(delay){
    if(delay == undefined) delay = 0;
    timer = setTimeout(object.next, 4500 + delay);
  };
  this.stop = function(){
    clearTimeout(timer);
  };
  this.initialize = function(selector, delay){
    this.stop();
    $slideshow = $("div.slider-home-slideshow", selector);
    $images = $("img", $slideshow);

    if($images.length > 1){
      object.start(delay);
    }
  };
  var changeSlide = function(){
    if(lock){
      return;
    }
    lock = true;
    next = $("img.active", $slideshow).index() + 1;
    if(next <= 0){
      $("img:eq(0)", $slideshow).addClass("active");
      next += 1;
    }
    if(next >= $images.length){
      next = 0;
    }

    $currentImg = $("img.active", $slideshow);
    $nextImg = $("img:eq("+next+")", $slideshow);
    if(next > $currentImg.index()){
      $nextImg.fadeIn(duration, function(){
        $currentImg.hide(0, function(){
          $currentImg.removeClass("active");
          $nextImg.addClass("active");
          lock = false;
          object.start();
        });
      });
    } else {
      $nextImg.show(0, function(){
        $currentImg.fadeOut(duration, function(){
          $currentImg.removeClass("active");
          $nextImg.addClass("active");
          lock = false;
          object.start();
        });
      });
    }
  }
}

