(function(SinemaTv, $) {
    var that = SinemaTv.broadcastGuide = {};

    SinemaTv.broadcastGuide._container = undefined;
    SinemaTv.broadcastGuide.timelineStart = undefined;
    SinemaTv.broadcastGuide.timelineEnd = undefined;
    SinemaTv.broadcastGuide.timelineMin = undefined;
    SinemaTv.broadcastGuide.timelineMax = undefined;

    var pixelPerMinute = 2.033; //TODO : golden ratio ?

    //Static data
    var oneDay = 60*60*24*1000; //one day in millisecs

    var showMetaData = ["showId",
                        "guideId",
                        "video",
                        "director",
                        "startTime",
                        "headLiners", 
                        "plot", 
                        "name",
                        "originalName",
                        "durationMinutes",
                        "genre",
                        "generation",
                        "image",
                        "video",
                        "videoThumbnail",
                        "movieDetailLink"
                        ];



    //Private functions
    var loading = SinemaTv.util.loading;


    /**
     * resize info box 
     */
    var resizeShowInfo = function(){
        var tvShows = that.tvShowsContainer.find(".tvShows");
        var tvChannels = that.tvChannelsContainer.find(".tvChannel");

        var selectedTvShowContainer = that.tvShowsContainer.find(".displayingDetails").parents(".tvShows");    
        var rowIndex = tvShows.index(selectedTvShowContainer);

        var infoHeight = that.infoBox.height() + 2;

        //tvShows.eq(rowIndex).css("margin-bottom", infoHeight);
        //tvChannels.eq(rowIndex).css("margin-bottom", infoHeight);
    };




    /**
     * Scroll tvshows and tv channels
     */
    var scrollContainers = function(marginTop){
        that.tvChannelsContainer.css("margin-top", marginTop + "px");
        that.tvShowsContainer.css("margin-top", marginTop + "px");
    };



    var dragDealerInitialized = false;

    /**
     * Check if scrollbar to be showed and set a scrollbar
     */
    var checkForScrollBar = function(){
        var outerContainer = that.guideScrollContent.find(".tvShowOverflow");
        var outerHeight = outerContainer.height();

        var innerMargin = -1 * parseInt(that.tvShowsContainer.css("margin-top"), 10);

        var innerHeight = that.tvShowsContainer.height();

        var diff = innerHeight - outerHeight;

        that.scrollBar.hide();
        if(diff > 0 || innerMargin > 0) {
            that.scrollBar.show();

            if(!dragDealerInitialized){

                var dealer = new Dragdealer("guideScrollbar",{
			    horizontal: false,
			    vertical: true,
			    animationCallback: function(x, y){
				var marginTop = -1 * parseInt(diff * y, 10);
				scrollContainers( marginTop);
			    }    
                });

                dragDealerInitialized = true;
            }

        }
    };


    /**
     * Increment or decrement date by given value
     * value should be negative to decrement
     */
    var incrementDateByValue = function(incrementBy){

        var incrementStatus = (incrementBy > 0) ? "increment" : "decrement";

        var currentTimeStamp = parseInt($(that.dateNavigation).attr("data-timestamp"), 10);
        var newTimeStamp = currentTimeStamp + incrementBy;

        //check for valid dates
        if(incrementStatus == "increment" && newTimeStamp > (that.timelineMax + oneDay)) {
           return false; 
        }
        else if(incrementStatus == "decrement" && (newTimeStamp + oneDay) < that.timelineMin) {
            return false;
        }


        $(that.dateNavigation).attr("data-timestamp", newTimeStamp);

        var newDateString = SinemaTv.util.formatDateFromTimestamp(newTimeStamp,"%d %M");
        $(that.dateSelectionText).html(newDateString);

        that.setTimelineStartEnd(); //set timeline start end again

        return true;
    };

    /**
     * return minute betwwen to timetamp in milliseconds
     */
    var getTimeDiffAsMinute = function(timestamp1, timestamp2){
        var result = parseInt( (timestamp1 - timestamp2) / 1000 / 60, 10);
        return result;
    };


    /**
     * Get pixel for hour and minute
     */
    var getPixelForHourAndMinute = function (timestamp) {
        var start = that.timelineStart;

        var minuteDiff = getTimeDiffAsMinute(timestamp, start.getTime());

        var pixels = minuteDiff * pixelPerMinute;

        return pixels;
    };



    /**
     * Add new tv channel
     */
    var addTvChannel = function(channelData){
        var channel = $("<div>").addClass("tvChannel");
        $("<img>").attr("src", channelData.logo).appendTo(channel);

        that.tvChannelsContainer.append(channel);
    };


    /**
     * Add new tv show and metadata
     */
    var addTvShow = function(channelId, tvShowData, container, nextGuideStartTime) {
        
        channelId = channelId || 0;

        //create DOM elements for a tvShow and append it to container
        var tvShow = $("<div>").addClass("tvShow").appendTo(container);
        var image = $("<img>").appendTo(tvShow).hide();
        var title = $("<h1>").appendTo(tvShow);
        var originalName = $("<div>").appendTo(tvShow);
        var genre = $("<div>").addClass("genre").appendTo(tvShow);

        var startTime = new Date();
        startTime.setTime(tvShowData.startTime);

        var guideDuration;
        if(nextGuideStartTime){
            //if next guideTime set, guide duration will be set to
            //diff between this time and end time
            guideDuration = getTimeDiffAsMinute(nextGuideStartTime, tvShowData.startTime);  
        }
        else {
            guideDuration = tvShowData.film.durationMinutes;

            //SINEMATV-274
            if(guideDuration == 0){ //if this is the last item which doesnt have any duration attribute
                var timelineEndForCurrentDate = new Date();
                timelineEndForCurrentDate.setTime( $(that.dateNavigation).attr("data-timeStamp") );
                timelineEndForCurrentDate.setHours(7);
                timelineEndForCurrentDate.setMinutes(0);
                timelineEndForCurrentDate.setSeconds(0);

                timelineEndForCurrentDate = timelineEndForCurrentDate.getTime() + oneDay;

                guideDuration = getTimeDiffAsMinute(timelineEndForCurrentDate, tvShowData.startTime);  
            }
        }

        var startPixel = getPixelForHourAndMinute(startTime.getTime());

        var width = guideDuration * pixelPerMinute;

        tvShow.css({left: startPixel, width: width});

        image.attr("src", tvShowData.film.image).show();

        tvShow.attr("title", tvShowData.film.name);

        var imageHidden = false;
        var tagLogoDisplayed = false;


        if( guideDuration > 0 && guideDuration <= 20 ) {
            tvShow.addClass("durationLessThen60").find("h1, div").hide();
            imageHidden = true;
        }
        else if( guideDuration > 20 && guideDuration <= 40 ) {
            tvShow.addClass("durationLessThen60").find("h1, div").hide();
            imageHidden = true;
        }
        else if (guideDuration > 40 && guideDuration <= 60){
            tvShow.addClass("durationLessThen60").find("h1, div").hide();
            imageHidden = true;
        }
        else if ( guideDuration > 60 && guideDuration <= 90 ){
            tvShow.find("img").hide();
            tvShow.find("h1, div").css("margin-left","4px");
            imageHidden = true;
        }



        var tags = tvShowData.film.tags;

        var allTags = $.merge([], tags.genres);
        allTags = $.merge(allTags, tags.labels);
        allTags = $.merge(allTags, tags.specialForYou);

        var itemTagCss = [];
        var cssPrefix = "itemLabel_";
        $.each(allTags, function(i, tag){
            if(tag.labelCssId) {
                if (channelId == 3 && tag.labelCssId == "hd") {
                    //SINEMATV-228
                    //channels except from "SinemaTV Aile" can have HD logo displayed
                    //ugly fix for SinematvAile === (channelID == 3)
                }
                else {
                    itemTagCss[itemTagCss.length] = cssPrefix + tag.labelCssId;
                    $("<span>").addClass(cssPrefix + tag.labelCssId).appendTo(tvShow);
                    if (tag.labelCssId == "hd") {
                        tagLogoDisplayed = true;
                    }
                }
            }
        });

        tvShow.addClass( itemTagCss.join(" ") );


        //determine truncate length of text
        var truncateWidth = width;
        if (!imageHidden){
            //if image displayed our width will be 85px lower
            truncateWidth = truncateWidth - 85;
        }
        if (tagLogoDisplayed){
            //if a tagLogo such as 'hd' displayed, width will be 22px lower
            truncateWidth = truncateWidth - 22; 
        }

        var truncateLength = parseInt(truncateWidth / 8);



        //truncate text which's length are much than 20
        title.html(SinemaTv.util.truncateText(tvShowData.film.name, truncateLength ));
        originalName.html(SinemaTv.util.truncateText(tvShowData.film.originalName, truncateLength ));
        genre.html( SinemaTv.util.truncateText(tvShowData.film.tags.defaultGenre.labelItemName, truncateLength ));

        
        //set metadata to tvShow containers data- attributes
        for(var i = 0; i < showMetaData.length; i++) {
            var attribute = showMetaData[i];
            var attributeValue = tvShowData.film[attribute];

            if( attribute == "startTime" ){
                attributeValue = tvShowData[attribute];
            }
            else if ( attribute == "genre" ) {
                attributeValue = tvShowData.film.tags.defaultGenre.labelItemName;
            }
            else if ( attribute == "generation" ) {
                attributeValue = tvShowData.film.tags.defaultGeneration.labelItemName;
            }
            else if ( attribute == "movieDetailLink" ) {
                attributeValue = tvShowData.film.link;
            }
            else if ( attribute == "showId" ) {
                attributeValue = tvShowData.film.id;
            }
            else if ( attribute == "guideId" ) {
                attributeValue = tvShowData.id;
            }

            tvShow.attr("data-" + attribute, attributeValue);
        }

    };

    /**
     * Generate TV shows from given JSON
     * called after getContent()
     */
    var generateTvShows = function(jsonData){
        that.errorContainer.hide();

        var channelsData = jsonData.channels;
        if(channelsData){

            $.each(channelsData, function(i, channelData){

                addTvChannel(channelData);
                var tvShowContainer = $("<div>").addClass("tvShows").appendTo(that.tvShowsContainer);


                var guideCount = channelData.guides.length;

                $.each(channelData.guides, function(i, tvShowData){
                    var nextGuideStartTime; 
                    if( (i + 1) < guideCount){
                        nextGuideStartTime = channelData.guides[i+1].startTime;
                    }

                    addTvShow(channelData.id, tvShowData, tvShowContainer, nextGuideStartTime);
                });

            });
        }

        checkForScrollBar();
        loading.stop(); //stop loading after generating shows
    };


    /**
     * Add one day to timeline
     */
    var addOneDayToTimeline = function(){
        var hoursContainer = that.guideScrollContent.find(".hours");
        var hoursForOneDay = hoursContainer.find(".hoursForOneDay").eq(0);
        hoursForOneDay.clone().appendTo(hoursContainer); //one day later

        var newWidth = that.guideScrollContent.width() + that.guideScrollContentWidth - 70;

        that.guideScrollContent.css("width", newWidth);
    };





    /**
     * Scroll content to up or down
     * scrollbar triggers that function
     */
    var scrollContent = function(direction){
        var currentMarginTop = parseInt(that.tvChannelsContainer.css("margin-top"), 10) || 0;
        var byPixel = 50;

        var containerHeight = parseInt(that.tvShowsContainer.height(), 10);
        //var tvShowHeight = parseInt(that.tvShowsContainer.find(".tvShow:first").height(), 10);

        var contentHeight = parseInt(that.guideScrollContent.find(".tvShowOverflow").height(), 10);

        var scrollHeight = containerHeight - contentHeight;

        if(direction == "up") {
            if( currentMarginTop < 0 ) {
                currentMarginTop += byPixel;      

                if( currentMarginTop > 0) {
                    currentMarginTop = 0;
                }
            }
        }
        else {
            //var outerContainerHeight = that.guideScrollContent.find(".tvShowOverflow").height();
            
            if( Math.abs(currentMarginTop - byPixel) < scrollHeight){
                currentMarginTop -= byPixel;
            }
            else {
                currentMarginTop = -1 * scrollHeight;
            }
        }

        scrollContainers(currentMarginTop);
    };


    /**
     * Hide info box
     */
    var hideInfoBox = function(dontResize){
        var containers = that.tvShowsContainer.find(".tvShows");
        
        //uncheck other itmes
        containers.find(".tvShow").removeClass("displayingDetails");

        var tvChannels = that.tvChannelsContainer.find(".tvChannel");

        $(containers).css("margin-bottom","0");
        $(tvChannels).css("margin-bottom","0");

        scrollContainers(0);

        if(!dontResize){
            //TODO: these pixels are here 'to save the day'
            that.guideMiddle.css("height","420px");
            that.lightBoxContainer.css("height", "540px");
            $.fn.colorbox.resize();
        }


        that.broadcastGuideContainer.css({"overflow":"hidden"});

        that.infoBox.hide();
    };

    /**
     * When clicked to a show, infobox will be filled
     * from data- attributes of this show
     */
    var fillInfoBox = function(element) {

        //determine if a current infobox is displaying and switching context 
        //of infobox
        var switching = (that.tvShowsContainer.find(".tvShow.displayingDetails").length > 0) ? true : false;

        hideInfoBox(switching);
        that.broadcastGuideContainer.css({"overflow":"visible"});
        that.infoBox.find(".filmInfo").show();

        var reminderInfo = that.infoBox.find(".reminderInfo");
        reminderInfo.hide();

        var containers = that.tvShowsContainer.find(".tvShows");
        $(element).addClass("displayingDetails");

        var parentContainer = $(element).parents(".tvShows");
        var rowIndex = $(containers).index(parentContainer);

        var videoElement = that.infoBox.find(".video");

        videoElement.html('');

        //traverse through data- attributes and fill related items
        for(var i = 0; i < showMetaData.length; i++){
            var attribute = showMetaData[i];
            var attributeValue = element.attr("data-"+attribute);


            //set video or thumbnail  (or both)
            if(attribute == "video") {
                var video = attributeValue;
                var videoThumbnail = element.attr("data-videoThumbnail");
                //if both video and thumbnail presents
                //create a videoplayer with a thubmnail
                if(video && videoThumbnail){
                    that.videoPlayer.setImage(videoThumbnail);
                    that.videoPlayer.setFlv(video);    
                    that.videoPlayer.putInto( videoElement );
                }
                else if (video) { //if only video presents
                    that.videoPlayer.setImage("");
                    that.videoPlayer.setFlv(video);
                    that.videoPlayer.putInto( videoElement );
                }
                else if (videoThumbnail){
                    // if only video presents, put an image instead of video 
                    var thumbImage = $("<div>").addClass("videoThumbnail")
                                               .css("background", "url('"+videoThumbnail+"')");

                    videoElement.html( thumbImage );
                }

            }
            //set start time in formatted date format
            else if(attribute == "startTime") {
                var formattedDate = SinemaTv.util.formatDateFromTimestamp(attributeValue, "%d.%m.%Y %D | Saat %H:%i");
                that.infoBox.find(".formattedDate").html(formattedDate);
                that.infoBox.find(".reminder").attr("data-timeOffset", attributeValue);
                that.infoBox.find(".reminder").attr("data-filmId", element.attr("data-showId"));
                that.infoBox.find(".reminder").attr("data-guideId", element.attr("data-guideId"));

            }
            //genre and generation will be appended with a , at the end
            else if(attribute == "genre" || attribute == "generation"){
                if(attributeValue){
                	that.infoBox.find("." + attribute).html(attributeValue + ",");
		        }
            }
            else if(attribute == "plot"){
                var truncated = SinemaTv.util.truncateText(attributeValue, 300);
                
                if(attributeValue.length > 300) {
                    var url = element.attr("data-movieDetailLink");
                    truncated += ' <a class="movieDetailLink" href="' + url + '">Devamı</a>';
                }

                that.infoBox.find(".plot").html( truncated );
                reminderInfo.find(".reminder_plot span").html(truncated);
            }
            else if(attribute == "showId"){
                reminderInfo.find("#guideReminderSubmit").attr("data-filmId", attributeValue);
                reminderInfo.find("#guideReminderSubmit").attr("data-guideId", element.attr("data-guideId"));
            }
            //set movie detail link
            else if(attribute == "movieDetailLink"){
                that.infoBox.find(".movieDetail").attr("href", attributeValue);
            }
            //replace elements html() with related attribute
            else {
                reminderInfo.find(".reminder_" + attribute +" span").html(attributeValue);
                that.infoBox.find("." + attribute).html(attributeValue);

            }

        }

        //if clicked after 2. row, scroll content to top
        /*if(rowIndex > 1){
            var marginTop = -60 * (rowIndex-1);
            that.tvChannelsContainer.css("margin-top", marginTop + "px");
            that.tvShowsContainer.css("margin-top", marginTop + "px");
        }
        */

        resizeShowInfo();

        //resize lightbox
        //TODO: these pixel heights are here 'to save the day'
        //that.guideMiddle.css("height","400px");
        //that.lightBoxContainer.css("height", "535px");
        //$.fn.colorbox.resize();

        var itemTop = $(element).offset().top + $(element).height() - that._container.offset().top;
      
        if (rowIndex >=3) { 
            var boxHeight = that.infoBox.height() + 60;
            itemTop = itemTop - boxHeight;
        }

        that.infoBox.css("height", "185px");
        that.infoBox.css("top", itemTop  + "px").show();
    };



    //when clicked to close
    var bindShowInfoCloseEvent = function(){
        that.infoBox.find(".close").click( function(){
            hideInfoBox();
        });
    };


    //when clicked to 'remind me' button
    var bindShowInfoReminder = function(){

        that.infoBox.find(".reminder").click( function(){
            that.reminderNotification.find("div").hide();
            var filmId = $(this).attr("data-filmId");
            var timeOffset = $(this).attr("data-timeOffset");

            SinemaTv.guideReminder.getNextGuideTimes( filmId, timeOffset, that.infoBox, that._container);

            that.infoBox.find(".filmInfo").hide();
            that.infoBox.find(".reminderInfo").show();
            resizeShowInfo();
        });
    };


    /**
     * Submit guide reminder data on click
     */
    var bindGuideReminderClick = function(){
        var guideReminderSubmitContainer = that.infoBox.find("#guideReminderSubmit");
        var submitButton = guideReminderSubmitContainer.find("input.submit");

        var actions = guideReminderSubmitContainer.parents("div.actions:first");

        var remindTimeSelect = actions.find("select.remindTime");
        var remindPeriodSelect = actions.find("select.remindPeriod");

        var showTimer;

        submitButton.click( function(){
            var remindTime = remindTimeSelect.find("option:selected").val();
            var remindPeriod = remindPeriodSelect.find("option:selected").val();
            var guideId = guideReminderSubmitContainer.attr("data-guideId");
            var email = actions.find(".emailAddress").val();

            //TODO: email validation should be in somewhere like Sinematv.validation
		    var isValidEmail = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email);

            clearTimeout(showTimer);
            that.reminderNotification.find("div").hide();

            if(isValidEmail) {
                SinemaTv.guideReminder.submit( guideId, remindPeriod, email, that.infoBox);
            }
            else {
                that.reminderNotification.find("div.emailNotValid").fadeIn(function(){
                    showTimer = setTimeout( function(){
                        that.reminderNotification.find("div").fadeOut();
                    }, 2000);
                });
            }
        });

    };


    /** END of Private functions **/

    /**
     * set broadcastGuide container
     * and map all DOM elements related to this container
     */
    SinemaTv.broadcastGuide.setContainer = function(element) {
        this._container = element;

        that.wrappedUrl = SinemaTv.core.getRootPath() + "guide/wrapped-list";

        this.guideNavigation = element.find(".navigation a");
        this.guideMiddleRight = element.find(".middleRight");
        this.guideMiddle = element.find(".middle");
        this.guideScrollContent = this.guideMiddleRight.find(".scrollContent");
        this.guideScrollContentWidth = this.guideScrollContent.width();
        this.tagElements = element.find(".tags .tag");
        this.dateNavigation = element.find(".dateNavigation");
        this.dateNavigationLinks = this.dateNavigation.find("a");
        this.dateSelectionText = element.find(".dateSelection span");
        this.primeTimeElement = this.guideMiddleRight.find(".primeTime");
        this.currentTimeHolderElement = element.find(".now");
        this.currentTimeHolderWidth = this.currentTimeHolderElement.find(".holder").width();
        this.tvChannelsContainer = element.find("#tvChannels");
        this.tvShowsContainer = $("#tvShowsContainer");
        this.errorContainer = element.find(".broadcastGuideError");
        this.scrollBar = this.guideMiddleRight.find(".scrollbar");

        this.lightBoxContainer = $("#broadcastGuideLightbox");
        this.broadcastGuideContainer = $("#broadcastGuide");

        this.infoBox = $(".infoBox");
        this.reminderNotification = this.infoBox.find(".reminderNotification");
        bindShowInfoCloseEvent();
        bindShowInfoReminder();
        bindGuideReminderClick();

        this.loadingElement = element.find(".loadingOverlay");
        loading.setElement(this.loadingElement);

        that.infoBox.find(".fancySelect select").hide();

        //init
        this.setTimelineStartEnd();
        this.initNavigation();
        this.initTagChangeEvents();
        this.initDateSelector();

        this.initCurrentTimeHolder();
        this.scrollToCurrentTime();
        this.getContent();
        this.handleTvShowClickEvents();
        this.bindScrollbarEvents();

        that.videoPlayer = new SinemaTv.ui.VideoPlayer();

        SinemaTv.ui.clearInputsOnFocus(that.infoBox);

    };

    /**
     * Set timeline start and end values
     * TODO: add one day to start and one day to end
     */
    SinemaTv.broadcastGuide.setTimelineStartEnd = function(){
        var timelineDate = $(this.dateNavigation).attr("data-timeStamp"); 
        var currentDay = new Date();
        var today = SinemaTv.util.formatDateFromTimestamp(currentDay.getTime(),"%Y-%m-%d");

        //start is current dates 07:00
        var start = new Date(), 
            tmpStart = new Date();
        start.setTime(timelineDate);

        tmpStart.setTime(timelineDate);

        start.setSeconds(0);
        start.setMilliseconds(0);
        start.setHours(7);
        start.setMinutes(0);
        //start.setTime( start.getTime());
       

        this.currentTimeHolderElement.hide();

        if(tmpStart < start){
            start.setTime(start.getTime() - oneDay);
            $(that.dateNavigation).attr("data-timestamp", start.getTime());
            var newDateString = SinemaTv.util.formatDateFromTimestamp(start.getTime(),"%d %M");
            $(that.dateSelectionText).html(newDateString);
        }

        if( today == SinemaTv.util.formatDateFromTimestamp(tmpStart.getTime(),"%Y-%m-%d") ){
            this.currentTimeHolderElement.show();
        }

        //end date is a one day later from start
        var end = new Date();
        end.setTime( start.getTime() + oneDay);

        that.timelineStart = start;
        that.timelineEnd = end;

        return this;
    };



    /**
     * holds data cache for dates
     */
    var dateCache = {};

    var getContentTimer,
        getContentXhr = {};

    /**
     * Get data for previous day and next of dateStart
     */
    var generateCacheForOtherDays = function(dateStart){

        var days = [dateStart - oneDay , dateStart + oneDay];

        var setCache = function(cacheKey, getData){
            if(getContentXhr && getContentXhr[cacheKey]){
                getContentXhr[cacheKey].abort();
            }

            var dateData = getData;
            dateData.dateStart = dateData.dateStart - (2*oneDay);

            getContentXhr[cacheKey] = $.getJSON(that.wrappedUrl, dateData, function(data){
                dateCache[cacheKey] = data; 
            });
        };

        var getData;
        for(var i = 0; i < days.length; i++){

            var dateToGet = days[i];
            var dateEnd = dateToGet + oneDay;
            getData = { dateStart: dateToGet, 
                        dateEnd: dateEnd };

            var cacheKey = parseInt(dateToGet / 1000, 10);

            if(! dateCache[cacheKey] ) {
                setCache(cacheKey, getData);
            }

        }


    };

    /**
     * Get content via AJAX for given timestamp and filter tags
     */
    SinemaTv.broadcastGuide.getContent = function(){


        loading.start();
        hideInfoBox();

        var timeStamp = $(this.dateNavigation).attr("data-timeStamp"); 

        var currentTimestamp = new Date().getTime();

        var today = SinemaTv.util.formatDateFromTimestamp(currentTimestamp,"%Y-%m-%d");
        var navigationDay = SinemaTv.util.formatDateFromTimestamp(timeStamp, "%Y-%m-%d");

        var getData = { dateStart: that.timelineStart.getTime(), 
                        dateEnd: that.timelineEnd.getTime() };




        that.tvChannelsContainer.html('');
        that.tvShowsContainer.find(".tvShows").remove();

        var cacheKey = parseInt(getData.dateStart / 1000, 10);

        if(! dateCache[cacheKey] ) {
            if(getContentXhr && getContentXhr[cacheKey]){
                getContentXhr[cacheKey].abort();
            }

            var dateData = getData;
            dateData.dateStart = dateData.dateStart - (2*oneDay);

            getContentXhr[cacheKey] = $.getJSON(that.wrappedUrl, dateData, function(data){

                that.timelineMin = data.guideDateRange.first;
                that.timelineMax = data.guideDateRange.last;
       
                dateCache[cacheKey] = data;

                //generate tvShows from jsonData
                generateTvShows(dateCache[cacheKey]);
                filterCallback();

                generateCacheForOtherDays(that.timelineStart.getTime());

                if(that.timelineStart < currentTimestamp && that.timelineEnd > currentTimestamp){
                    that.scrollToCurrentTime();
                }


            });
       }
       else {

            generateCacheForOtherDays(that.timelineStart.getTime());
            //generate tvShows from jsonData
            generateTvShows(dateCache[cacheKey]);
            filterCallback();

            if(that.timelineStart < currentTimestamp && that.timelineEnd > currentTimestamp){
                that.scrollToCurrentTime();
            }
       }

    };


    /**
     * init hour navigation 
     */
    SinemaTv.broadcastGuide.initNavigation = function(options) {
        var defaultOptions = {
            incrementBy : "600"
        };

        //extend from global options
        options = $.extend(defaultOptions, options);

        var animating = false; //holds current animating status

        //bind click events to navigation 
        this.guideNavigation.click( function(){

            hideInfoBox();

            that.guideMiddleRightWidth  = that.guideMiddleRight.width();

            var currentWidth = parseInt($(that.guideScrollContent).width() - that.guideMiddleRightWidth, 10);

            var minusWidth = parseInt(-1 * currentWidth, 10);

            var currentMargin = parseInt( that.guideScrollContent.css("margin-left"), 10);

            var marginLeft = "";
            var type = "";
            var animationDuration = 100;

            //if animating already do nothing
            if( !animating ) {

                //if next button clicked move content to left
                if( $(this).hasClass("next")) {
                   type = "next";
                    marginLeft = "-=" + options.incrementBy;

                    //if last incremention
                    if( (currentMargin - options.incrementBy) < minusWidth ) {
                        marginLeft = minusWidth;
                    }

                    //move till end of content
                    if( currentMargin <= minusWidth ) {
                        if( incrementDateByValue(oneDay) ){
                            //if not end of valid dates
                            marginLeft = "0px";
                            animationDuration = 100;
                            that.getContent();
                        }
                    }

                }
                else { //move content to right

                    type = "prev";
                    marginLeft = "+=" + options.incrementBy;

                    //if last decrementation
                    if( (currentMargin + parseInt(options.incrementBy, 10)) > 0){
                        marginLeft = "0px";
                    }

                    //move till beginning of content
                    if( currentMargin >= 0 ) {
                        if( incrementDateByValue(-oneDay) ) {
                            marginLeft = minusWidth;
                            animationDuration = 100;
                            that.getContent();
                        }
                    }

                }

                animating = true; 

                $(that.guideScrollContent).animate({
                    "margin-left": marginLeft
                }, animationDuration, function() {
                    //animation finished
                    animating = false; 
                });
            }
        });
    };



    var filterCallback = function() {
       hideInfoBox();
            var selectedFilterTags = that._container.find(".tags .tag.active");

            if(selectedFilterTags.length > 0 ){
                that.tvShowsContainer.find(".tvShow").addClass("notMatched").fadeTo(0, 0.2);
            }
            else {
                that.tvShowsContainer.find(".tvShow").removeClass("notMatched").fadeTo("fast",1);
            }

            for(var i = 0 ; i< selectedFilterTags.length; i++) {
                var item = selectedFilterTags[i];
                if( selectedFilterTags.hasOwnProperty(i) ) {
                    var filterValue = $(item).attr("data-filter");
                    that.tvShowsContainer.find(".tvShow."+filterValue).removeClass("notMatched").fadeTo("fast", 1);
                }
            }
    };


    /**
     * Handle click events on tags
     */
    SinemaTv.broadcastGuide.initTagChangeEvents = function(callback){
        callback = callback || function(){
            filterCallback();     
        };

        this.tagElements.click( function(e){
            e.preventDefault();
            $(this).toggleClass("active");               
            callback();
        });
    };



    /**
     * date selector  on top left
     */
    SinemaTv.broadcastGuide.initDateSelector = function(callback) {
        callback = callback || function(){
            that.getContent();
        };

        this.dateNavigationLinks.click( function(e) {
            e.preventDefault();

            if($(this).hasClass("next")){
                incrementDateByValue(oneDay);
            }
            else {
                incrementDateByValue(-oneDay);
            }

            //call function
            callback();
            
        });
    };


    /**
     * set primetime line
     */
    SinemaTv.broadcastGuide.setPrimeTime = function (startHour, startMinute, endHour, endMinute) {

        var dayDiff = Math.ceil((that.timelineEnd - that.timelineStart) / oneDay);

        for(var i=0; i<dayDiff; i++){

            if(i>0){
                //Expand timeline
                addOneDayToTimeline();
            }

            var timestamp = (that.timelineStart.getTime()) + (oneDay*i);
            var primeTime = new Date();
            primeTime.setTime(timestamp);
            primeTime.setHours(startHour);
            primeTime.setMinutes(startMinute);

            var startPixel = getPixelForHourAndMinute(primeTime.getTime());

            if(endHour < startHour){
                primeTime.setTime(timestamp + oneDay);
            }

            primeTime.setHours(endHour);
            primeTime.setMinutes(endMinute);

            var tenMinutes = 600000; //in milliseconds

            var endPixel = getPixelForHourAndMinute(primeTime.getTime() - tenMinutes);
            var duration = parseInt( endPixel - startPixel, 10);

            var css = {"margin-left": startPixel, "width": duration};

            that.primeTimeElement.clone().css(css).prependTo(that.guideScrollContent).show();
        }
    };


    /**
     * put red line which indicates current time
     */
    SinemaTv.broadcastGuide.initCurrentTimeHolder = function() {
        var currentTime = new Date();
        var startPixel = getPixelForHourAndMinute(currentTime.getTime());

        var holderWidth = that.currentTimeHolderElement.width();

        var marginLeft = startPixel - (holderWidth/2);

        this.currentTimeHolderElement.css("margin-left", marginLeft );
    };

    /**
     * Scroll timeline to current time
     */
    SinemaTv.broadcastGuide.scrollToCurrentTime = function(){
        var currentMargin = parseInt(this.currentTimeHolderElement.css("margin-left"), 10);
        var contentWidth = this.guideMiddleRight.width();
        var scrollContentWidth = this.guideScrollContent.width();

        var currentTimesPosition = getPixelForHourAndMinute( new Date().getTime() );

        var halfContentWidth = contentWidth / 2;
        var marginLeft = -1 * (currentMargin - halfContentWidth);

        if( (currentMargin + contentWidth) >= scrollContentWidth) {
            marginLeft = -1 * (scrollContentWidth - contentWidth);
        }

        if(marginLeft > 0 ){
            marginLeft = 0;
        }

        if(marginLeft > 0 ){
            marginLeft = 0;
        }

        this.guideScrollContent.css("margin-left", marginLeft + "px");

    };

    /**
     * Bind click events on tvShows
     * A popup will be displayed on tvShow's click
     */
    SinemaTv.broadcastGuide.handleTvShowClickEvents = function(){

        //click on active items after filtering
        that._container.delegate(".tvShow:not(.notMatched)", 'click', function(e) {
            e.preventDefault();


            //SINEMATV-381
            //var url = $(this).attr("data-movieDetailLink");
            //window.location.href = url;
            //return false;

            //if click again on detail displaying show, hide infobox
            if( $(this).hasClass("displayingDetails") ) {
                hideInfoBox();
            }
            else {
                fillInfoBox($(this));
            }
        });
    };

    SinemaTv.broadcastGuide.bindScrollbarEvents = function(){
        that.guideMiddleRight.find(".scrollbar a").click( function(){

            hideInfoBox();

            if( $(this).hasClass("pageUp") ){
                scrollContent("up");
            }
            else {
                scrollContent("down");
            }
        });
    };

})(SinemaTv, jQuery);

