//INCLUDE: common.js
//INCLUDE: ajaxHistory.js
//INCLUDE: loader.js
//INCLUDE: image-preloader.js

$(document).ready(function(){
  
  //Fix all PNGs
  fixPNG();

  //Init History
  $.ajaxHistory.init(function(){},{});
  $.ajaxHistory.addCallback(function(){
    var url = window.location.hash.replace("#","");
    if(url == ""){
      url = window.location.pathname;
    }
    var params = {
      history: false,
      callbk_success: function( html ){
        var lastRequest = LOADER.getLastRequest();
        CONTENT.fadeInNewContent( html, 500, lastRequest, function(){
          SLIDESHOW.init(lastRequest.id);
        })
      }
    };
    LOADER.request(url,params);
  })
  
  IMAGE_PRELOADER.init("#preloader");
  LOADER.init();
  NAV.init();
  
  //Hide current page contents
  CONTENT.hide();
    
  //Function to show page contents
  var show_page = function(html){
      var thisRequest = LOADER.getLastRequest();
      var thisRequestID = thisRequest.id;
      
      //Show the navigation
      NAV.show(function(){
        CONTENT.setContent( html, thisRequest, function(){
          CONTENT.init();
          CONTENT.show(1000, function(){
            //Init slideshow and start it
            SLIDESHOW.init(thisRequestID, function(){
              SLIDESHOW.stopPlay();
            });
          })
        });
      });
  }
  
  var show_error = function(){
    // Do something
  }
  
  //Get URL from the current hash
  var url = window.location.hash.replace("#","");
  if(url == ""){
     url = window.location.pathname;
  }
  
  //Request page specified in the hash
  LOADER.request(url,{
      callbk_success: show_page,
      callbk_error: show_error,
      history: false,
      allow_duplicates: true
  });
  
});

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//     N A V I G A T I O N

var NAV =  function(){
  
  var container;
  var links;
  var STATE_HIDDEN = 0;
  var STATE_SHOWING = 1;
  var currentState = STATE_HIDDEN;
  
  /**
   * Initialize the navigation
   */
  function init(){
    currentState = STATE_HIDDEN;
    
    container = $(".navigation-pane");
    links = container.find("a");

    //Remove links and replace them with AJAX calls
    links.each(function(){
      
      var url = $(this).attr("href");
      $(this).removeAttr("href");
      
      var params = {
        
        callbk_success: function( html ){
          var lastRequest = LOADER.getLastRequest();
          
          if( $(html).find(".image-scroller").length > 0 ){
            CONTENT.slideInNewContent( html, 500, lastRequest, function(){
              //Init slideshow and start it
              SLIDESHOW.init(lastRequest.id, function(){
                SLIDESHOW.stopPlay();
              });
            });
          }else{
            CONTENT.fadeInNewContent( html, 500, lastRequest, function(){
              //Init slideshow and start it
              SLIDESHOW.init(lastRequest.id, function(){
                SLIDESHOW.stopPlay();
              });
            });
          }

        }
      };

      $(this).parent().click(function(){
        if(currentState != STATE_SHOWING){
          return;
        }
        LOADER.request(url,params);
      });
    });

    //Hide navigation content
    $(".line1, .line2, .line3, .line4, .line5, .line6, .line7").css({opacity: 0, display: "none"});

    //Refresh Cufon text on mouse over
    links.parent().hover(function(){
      $(this).find("a").addClass("hover");
    },function(){
      $(this).find("a").removeClass("hover");
    });
  }
  
  /**
   * Display navigation content line-by-line.
   * Executes a callback when the navigation has been fully displayed.
   */
  function show(callback){
    
    //Preload navigation links first
    $(".loading-spinner").show(0);
    IMAGE_PRELOADER.preload(links, function(){
      //Preload navigation link hover states
      links.addClass("hover");
      IMAGE_PRELOADER.preload(links, function(){
        links.removeClass("hover");
        //Preload slideshow controls
        IMAGE_PRELOADER.preload(container.find(".ctrl-stop-play, .ctrl-frwd, .ctrl-back"), function(){
          $(".loading-spinner").hide(0);
          showLines(1);

          //Show navigation line by line
          function showLines(lineNum){

              if(lineNum <= 6){
                var lineElements = $(".line" + lineNum);
                if(lineElements){
                  lineElements.css("display","block")
                  var barrier = new BarrierSync(lineElements.length);
                  lineElements.each(function(i){
                    $(this).stop().animate({opacity: 1},550,"linear",barrier.getNotifier(i));
                  });
                  //When this line has finished showing, show the next one
                  barrier.wait(200, function(){
                      showLines(lineNum + 1);
                  });
                }else{
                  showLines(lineNum + 1);
                }
              }else{
                currentState = STATE_SHOWING;
                doCallback(callback);
              }

          }
        });
      });
    });
  }
  
  return {init:init, show:show};
}();

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//     C O N T E N T

var CONTENT = function(){

  var content;
  var content_overlay;

  /**
   * Initialize the page content
   */
  function init(requestID){
    
    Contact.init();
    
    //Get all content not marked for deletion
    content = $(".content-pane:not(.delete)");
    //Get overlay that hides content
    content_overlay = $(".content-overlay");
    
    //Highlight the new selected elements (this should be the navigation link associated with this content)
    $(".selected").removeClass("selected");
    var highlighted = $(content.attr("rel"));
    $(highlighted).addClass("selected");

    //Protect slideshow images from copying
    if($(content).find(".image-scroller").length > 0){
      CONTENT.protectSlideshow();
    }else{
      $(".image-scroller").remove();
    }
    
    //Replace text content with Cufon font
    Cufon.replace('p');
    Cufon.replace('h3');
    Cufon.replace('ul.awards li');
    Cufon.replace('form');
  }

  /**
   * Shows an overlay over the content so that it is invisible.
   */
  function hide(){
    if(content_overlay){
      content_overlay.css({opacity: 1, display: "inline"});
    }
  }

  /**
   * Display page content.
   * Executes a callback when the content is displayed.
   */
  function show(time, callback){
    //Preload images first
    $(".loading-spinner").show(0);
    IMAGE_PRELOADER.preload(content.find(".preload1"), function(){
      //Fade out the overlay to gradually make content visible
      content_overlay.animate({opacity: 0},time,"linear", function(){
        //Hide the overlay such that it takes up no space in the document
        content_overlay.css("display","none");
        $(".loading-spinner").hide(0);
        doCallback(callback);
      });
    });
  }
  
  /**
   * Put an overlay over the slideshow so they can not be copied
   */
  function protectSlideshow(){
    if(content){
      content.append("<div class='slideshow-overlay'></div>");
      var overlay = $(".slideshow-overlay");
      var img = $('<img />');
      img.attr("src","/images/overlay.gif");
      img.css("width","100%");
      img.css("height","100%");
      overlay.append(img);
    }
  }
  
  /**
   * Slides in new contents from the right.
   */
  function slideInNewContent(newPage, transition_time, request, callback){

    LOADER.lock();

    //Stop any slideshows
    SLIDESHOW.stop();
    SLIDESHOW.disable();  //lock slideshow controls
    
    //Get current content
    var currentContent = $(".content-pane");
    currentContent.addClass("delete");

    //Get the loaded page content
    var newContent = $(newPage).find(".content-pane");
    
    //Create an 'off-screen' content pane
    $(".frame").append("<div class='content-pane off-screen rID" + request.id + "' rel='" + $(newContent).attr("rel") + "'></div>");
    var offScreenPanel = $(".content-pane.off-screen.rID" + request.id);
    
    //Append loaded contents to off-screen panel
    $(offScreenPanel).append($(newContent).children());
    
    //Init new content
    CONTENT.init();

    //Wait for content to preload before proceeding, at this point we allow LOADER interrupts
    LOADER.unlock();
    $(".loading-spinner").show(0);
    IMAGE_PRELOADER.preload($(".content-pane .preload1"), function(){
     
      //If this request was interrupted, do not proceed with it
      if(LOADER.getLastRequest().id != request.id){
        offScreenPanel.remove();
        return;
      }else{
        LOADER.lock();
      };
      
      //Shift current content offscreen to left
      currentContent.stop().animate({left: -$(".frame").width()},transition_time,"linear");
      //Shift new content onscreen from right
      offScreenPanel.stop().animate({left: 0}, transition_time, "linear", function(){
        //Remove old content when new content is on screen
        $(currentContent).stop().remove();
        $(offScreenPanel).removeClass("off-screen");
              
        Cufon.refresh();
      
        //Request has completed, we can now process new requests
        LOADER.unlock();
        request.state = "COMPLETED";
        doCallback(callback);
      });
    });
  }
  
  /**
   * Fade in new content.
   */
// ?? Much duplicate code in here and slideInNewContent
  function fadeInNewContent(newPage, transition_time, request, callback){

    LOADER.lock();

    //Stop any slideshows
    SLIDESHOW.stop();
    SLIDESHOW.disable();  //lock slideshow controls
    
    //Get current content
    var currentContent = $(".content-pane");
    $(currentContent).addClass("delete");

    //Get the loaded page content
    var newContent = $(newPage).find(".content-pane");
    
    //Put new content behind old content
    $(".frame").prepend("<div class='content-pane behind rID" + request.id + "' rel='" + $(newContent).attr("rel") + "'></div>");
    var offScreenPanel = $(".content-pane.behind.rID" + request.id);
    
    //Append loaded contents to off-screen panel
    $(offScreenPanel).append($(newContent).children());
    
    //Init new content
    CONTENT.init();

    //Wait for content to preload before proceeding, at this point we allow LOADER interrupts
    LOADER.unlock();
    $(".loading-spinner").show(0);
    IMAGE_PRELOADER.preload($(".content-pane .preload1"), function(){
     
      //If this request was interrupted, do not proceed with it
      if(LOADER.getLastRequest().id != request.id){
        offScreenPanel.remove();
        return;
      }else{
        LOADER.lock();
      };
      
      //Fade out old content
      currentContent.stop().fadeOut(transition_time, function(){
        currentContent.remove();
        $(offScreenPanel).removeClass("behind");
        Cufon.refresh();
        //Request has completed, we can now process new requests
        LOADER.unlock();
        request.state = "COMPLETED";
        doCallback(callback);
      });
    });
  }
  
//?? AGAIN - Much duplicate code
  function setContent(newPage, request, callback){
      LOADER.lock();

      //Stop any slideshows
      SLIDESHOW.stop();
      SLIDESHOW.disable();  //lock slideshow controls

      //Get current content
      var currentContent = $(".content-pane");
      $(currentContent).addClass("delete");

      //Get the loaded page content
      var newContent = $(newPage).find(".content-pane");

      //Put new content behind old content
      $(".frame").append("<div class='content-pane behind rID" + request.id + "' rel='" + $(newContent).attr("rel") + "'></div>");
      var offScreenPanel = $(".content-pane.behind.rID" + request.id);

      //Append loaded contents to off-screen panel
      $(offScreenPanel).append($(newContent).children());

      //Init new content
      CONTENT.init();

      //Wait for content to preload before proceeding, at this point we allow LOADER interrupts
      LOADER.unlock();
      $(".loading-spinner").show(0);
      IMAGE_PRELOADER.preload($(".content-pane .preload1"), function(){
        $(".loading-spinner").hide(0);

        //If this request was interrupted, do not proceed with it
        if(LOADER.getLastRequest().id != request.id){
          offScreenPanel.remove();
          return;
        }else{
          LOADER.lock();
        };

        //Replace old content
        currentContent.remove();
        $(offScreenPanel).removeClass("behind");
        Cufon.refresh();
        //Request has completed, we can now process new requests
        LOADER.unlock();
        request.state = "COMPLETED";
        doCallback(callback);
      });
  }
  
  return {init:init, hide:hide, show:show, slideInNewContent:slideInNewContent, fadeInNewContent:fadeInNewContent, setContent:setContent, protectSlideshow:protectSlideshow};
  
}();

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//     S L I D E S H O W

var SLIDESHOW = function(){
  var slideshowID = 0;
  var playCount = 0;
  var imageIx = 0;                    //Index of current image in the list being viewed in the slideshow (the most centred)
  var imageCount = 0;                 //Number of images in the slideshow
  var slideshowWidth = 0;             //Width of the slideshow in pixels
  var imageOffsets = null;            //The distance each image center is from the left of the scroller
  var imageWidths = null;             //The width of each image in the slideshow
  var maxScroll = 0;                  //Maximum amount the scroller may scroll
  var scroller = null;                //The list of image elements
  
  var STATE_STOP = 0;                  //Stops auto-scrolling of slideshow
  var STATE_PLAY = 1;                  //Resumes auto-scrolling of slideshow
  var STATE_DISABLE = 2;               //Disables all slideshow controls
  var currentState = 2;                //Current state
  
  function init(requestID, callback){
    //Assign a new slideshow ID
    slideshowID++;
    
    scroller = $(".content-pane .image-scroller");
    var scrollerContent = scroller.find("li");

    imageIx = 0;
    imageCount = scrollerContent.length;
    slideshowWidth = 0;
    currentState = STATE_DISABLE;

    //Ensure slideshow images are loaded before starting
    $(".loading-spinner").show(0);
    IMAGE_PRELOADER.preload($(".image-scroller").find(".preload1, .preload2"), function(){
      $(".loading-spinner").hide(0);

      //If no scroller, we may have a page to transition to
      if(scroller.length <= 0){
        disable();
        
        //Hide controls
        $(".ctrl-back").hide();
        $(".ctrl-stop-play").hide();
        $(".ctrl-frwd").hide();

        //If a link exists, make a request after a delay
        var slideshowLink = $("a.next-slideshow:first")
        if( slideshowLink.length > 0){
           
          var nextURL = $(slideshowLink).attr("href");
          var transitionDelay = parseInt(slideshowLink.attr("rel"));

          setTimeout(function(){
            if(requestID == LOADER.getLastRequest().id){
              var params = {
                callbk_success: function( html ){
                  var lastRequest = LOADER.getLastRequest();
                  CONTENT.fadeInNewContent( html, 1000, lastRequest, function(){
                    //Init slideshow and start it
                    SLIDESHOW.init(lastRequest.id, function(){
                      stopPlay();
                    });
                  });
                }
              }
              LOADER.request(nextURL,params);
            }
          },transitionDelay);
        }
        return;
      }

      var rightPadding = parseInt(scroller.css("padding-right").replace("px",""));
      var leftPadding = parseInt(scroller.css("padding-left").replace("px",""));
    
      //Attach slideshow controls
      //Show controls
      $(".ctrl-back").show();
      $(".ctrl-stop-play").show();
      $(".ctrl-frwd").show();
      $(".ctrl-back").click(back);
      $(".ctrl-stop-play").click(stopPlay);
      $(".ctrl-frwd").click(forward);
    
      //Determine width of scrolling content, their left offsets and widths
      imageOffsets = new Array();
      imageWidths = new Array();
      $(scrollerContent).each(function(){
        slideshowWidth = slideshowWidth + $(this).width();
        imageOffsets.push(slideshowWidth - ($(this).width()/2) + leftPadding );
        imageWidths.push($(this).width());
      });
    
     //Determine how far we can scroll
     maxScroll = slideshowWidth - scroller.parent().width() + rightPadding + leftPadding;
     if(maxScroll < 0){
       maxScroll = 0;
     }
    
     //Ensure scroller is the correct width
     scroller.css("width",slideshowWidth);
 
     //Slideshow is now ready
     currentState = STATE_STOP;
     doCallback(callback);
   });
  }
  
  function forward(){
    if(imageIx < imageCount - 1){
      if(currentState == STATE_STOP){
        imageIx ++;
        scrollTo(imageIx,300);
      }
    }
    
    if(currentState == STATE_PLAY){
      stop();
      forward();
    }
  }
  
  function back(){
    if(imageIx > 0){
      if(currentState == STATE_STOP){
        imageIx --;
        scrollTo(imageIx,300);
      }
    }
    
    if(currentState == STATE_PLAY){
      stop();
      back();
    }
  }
  
  function scrollTo(ix, transition_time, delay, callbk){

    if(ix >= imageCount || ix < 0){
      return;
    }
    
    var scrollViewWidth = $(scroller).parent().width();
    var currentOffset = -$(scroller).position().left;
    var scrollToCoords = imageOffsets[ix] - (scrollViewWidth/2);
    if(scrollToCoords > maxScroll){
      scrollToCoords = maxScroll;
    }
    if(scrollToCoords < 0){
      scrollToCoords = 0;
    }
    
    //If we are already there, return immediately
    if(currentOffset == scrollToCoords){
      doCallback(callbk);
      return;
    }

    //var delay = Math.abs(scrollToCoords - currentOffset)*30
     scroller.stop().animate({left: -scrollToCoords},transition_time,"easeInOutSine",function(){
       setTimeout(function(){
          doCallback(callbk);
       },delay);
     });
  }
  
  function stopPlay(){

    playCount ++;
    var thisToggleID = playCount;

    if(imageCount <= 0){
      return;
    }
    
    var scrollViewWidth = scroller.parent().width();
    var currentID = slideshowID;
    
    //Toggle state
    if(currentState == STATE_STOP){
      currentState = STATE_PLAY;
      $(".ctrl-stop-play").addClass("playing");
    
      var scrollNext = function(i){
        if(i < imageCount
          && currentState == STATE_PLAY
          && slideshowID == currentID
          && thisToggleID == playCount){
      
               scrollTo(i,600,3000,function(){scrollNext(i + 1);})
        }else{
          //If we have reached the end of the slideshow, load the next one
          if(i == imageCount){
             var nextSlideshowLink = $("a.next-slideshow");
             if(nextSlideshowLink.length > 0){
             
                var params = {
                  callbk_success: function( html ){
                    var lastRequest = LOADER.getLastRequest();
                    CONTENT.slideInNewContent( html, 600, lastRequest, function(){
                      //Init slideshow and start it
                      init(lastRequest.id, function(){
                        stopPlay();
                      });
                    });
                  }
                };
               LOADER.request($(nextSlideshowLink).attr("href"),params);
             }
          }
        }
      }
      
      setTimeout(function(){
        scrollNext(imageIx + 1);
      },3000);
      
    }else{
      stop();
    }
  }
  
  function stop(){

    if(imageCount <= 0){
      return;
    }
    
    if(currentState == STATE_PLAY){
    
      //?? add padding to this??
      var currentOffset = scroller.position().left;
    
      currentState = STATE_STOP;
      $(".ctrl-stop-play").removeClass("playing");
    
      //Stop sliding slideshow
      scroller.stop();
    
      //Calculate new current image index
      var scrollerContent = scroller.find("li");
      var estimatedIx = 0;
      $(scrollerContent).each(function(i){

        //Test for intersection
        var leftBound = imageOffsets[i] - (imageWidths[i]/2);
        var rightBound = imageOffsets[i] + (imageWidths[i]/2);
        if(leftBound <= -currentOffset && -currentOffset <= rightBound){
          estimatedIx = i + 1;
        }
      
      });

      imageIx = estimatedIx;
      
    }
  }
  
  function disable(){
    currentState = SLIDESHOW.STATE_DISABLE;
  }
  
  return{init:init, stop:stop, stopPlay:stopPlay, disable:disable};
}();

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//     C O N T A C T     M A I L E R

var Contact = {
  
  requiredFields:
  {
    name:{message:"Please enter your name"},
    email:{message:"Please enter your email address"}
  },
  
  animationDuration: 600,
  
  init: function(){
    $("#contact-form .submit").unbind().click(Contact.validate);
  },
  
  validate: function(){
    
    if (Contact.pendingRequest) return; //dont do anything if weve already hit submit
    
    var elements = $("#contact-form").find("input, select");
    var vars = {};
    
    //remove any previous style from other failed validations
    elements.attr("style", " ");
    
    elements.each(function(){
      if(this.type == "radio"){
        if(this.checked) vars[this.name] = this.value;
      } else if(this.type == "checkbox"){
        if(this.checked) vars[this.name] = this.value;
      } else {
        vars[this.name] = this.value;
      }
    });
    
    var failedFields = {};
    var valid = true;
    var requiredFields = Contact.requiredFields;
    
    //check for required fields
    for(var i in requiredFields){
      
      if(vars[i]){//does this var exist?
        
        if(requiredFields[i].regexp){
          if(!requiredFields[i].regexp.test(vars[i])){//test the regexp
            valid = false;
            failedFields[i] = requiredFields[i];
          }
        } else if(vars[i].length < 1) { //is the string too short?
          valid = false;
          failedFields[i] = requiredFields[i];
        }
        
      } else {
        valid = false;
        failedFields[i] = requiredFields[i];
      }
    }
    
    if(valid){
      //submit it    
      Contact.submit(vars);
      $("#contact-form .submit").remove();
    } else {
      //hilight failed fields
      Contact.hilight(failedFields);
    }
    
    //prevent default action
    return false;
    
  },
  
  submit: function(vars){
    
    vars.ajax = true;
    
    if (Contact.pendingRequest){
      Contact.pendingRequest.abort();
    }
    
    Contact.pendingRequest = $.post( "/mailer.php", vars, Contact.requestComplete);
    
    //prevent default action
    return false;
    
  },
  
  requestComplete: function(result){
    
    Contact.pendingRequest = null;
    
    var resultJSON = eval('('+result+')');
    
    if(resultJSON.success == true){
      
      Contact.success();
      
    } else {
      var failedFields = {};
      if(resultJSON.fields){
        for(var i in resultJSON.fields){
          failedFields[i] = Contact.requiredFields[i];
        }
      }
      //hilight failed fields
      Contact.hilight(failedFields);
    }
  },
  
  success: function(){
    Contact.createFeedbackElement();
    Contact.feedbackElement.append("Thankyou for joining, we'll be in touch shortly.");
    Contact.feedbackElement.hide();
    Contact.feedbackElement.slideDown(0);
  },
  
  hilight: function(failedFields){
    
    Contact.createFeedbackElement();
    
    Contact.feedbackElement.append("There are problems with the information you entered. <br/> Please check the following fields:");
    var ul = $("<ul></ul>");
    Contact.feedbackElement.append(ul);
    
    for(var i in failedFields){
      var field = $("#contact-form").find("#"+i);
      //field.css({backgroundImage:"none", backgroundColor: Loader.currentPage.color});
      ul.append($("<li>"+failedFields[i].message+"</li>"));
    }
    
    Contact.feedbackElement.hide();
    Contact.feedbackElement.slideDown(0);
    
  },
  
  createFeedbackElement: function(){
    //remove any previous feedback elements
    if(Contact.feedbackElement) Contact.feedbackElement.stop().slideUp(0, function(){
      $(this).remove();
    });
    
    Contact.feedbackElement = $("<div class='form-feedback'></div>");
    $("#contact-form").prepend(Contact.feedbackElement);
  }
  
}