﻿
var elementManager = new ElementManager();
var validation = new Validation();
var eventManager = new EventManager();
var calendarManager = new CalendarManager();
var customerDetailsManager = new CustomerDetailsManager();

var userAgent = navigator.userAgent.toLowerCase();
var isIE = userAgent.indexOf('ie') != -1 ? true : false;
var isChrome = userAgent.indexOf('chrome') != -1 ? true : false;
var isSafari = userAgent.indexOf('safari') != -1 ? true : false;
var isMac = userAgent.indexOf('mac') != -1 ? true : false;
var scrollTop = false;

function $g(id){   
    return document.getElementById(id);
}
function $$(element,tagName){   
    return element.getElementsByTagName(tagName);
}
 function isUndefined(obj){
    return 'undefined' == typeof obj;
}
function ElementManager(){
    this.SetTrailWizard = SetTrailWizard;
    this.GetElementPosition = GetElementPosition;
    this.ShowFullImage = ShowFullImage;
    this.HideFullImage = HideFullImage;
    this.UnCheckTimeSlotCheckBoxes = UnCheckTimeSlotCheckBoxes;
    this.SetFocusWithDelay = SetFocusWithDelay;
    this.Trim = Trim;
    this.Engage = Engage;
    this.ShowPopupDiv = ShowPopupDiv;
    this.SetDefaultWidth = SetDefaultWidth;
    this.SetActiveMenu = SetActiveMenu;
    this.ShowTotal = ShowTotal;
    this.SetScrollTop = SetScrollTop;
    this.ReplicateNextLinkClick = ReplicateNextLinkClick;
    this.ShowCarousel = ShowCarousel;
    this.SetPostCode = SetPostCode;
    this.SetLocation = SetLocation;
    var offsetX = null;
    var offsetY = null;
    
    function SetPostCode(location){
        if(location.selectedIndex == 1){ // if have selected depot clear post code selection
            // FF and other browsers have a text node element between the li siblings
            var nextLi = isIE ? location.parentNode.nextSibling : location.parentNode.nextSibling.nextSibling;
            var postCode = $$(nextLi, 'select')[0];
            postCode.selectedIndex = 0;
        }
    }
    function SetLocation(postCode){
        // FF and other browsers have a text node element between the li siblings
        var previousLi = isIE ? postCode.parentNode.previousSibling : postCode.parentNode.previousSibling.previousSibling;
        var location = $$(previousLi, 'select')[0];
        // select depot or van to you depending on whether a post code has been selected
        location.selectedIndex = postCode.selectedIndex == 0 ? 1 : 0;
    }
    function SetScrollTop(){
        document.body.style.cursor = 'default';
        // need to bind scrollTop to the window namespace as if it we just use scrollTop and
        // it doesn't exist at all then any function call with it will fail
        if(!isUndefined(window.scrollTop) && window.scrollTop){
            document.documentElement.scrollTop = 0;
        }
    }
    function ReplicateNextLinkClick(){
        var nextLink = $g(wizardNextID);
        var wizardNext = $g('wizardNext');
        wizardNext.href = nextLink.href;
        
        // 17-Jan-2010 - JB - removed the following line and instead added the function call to the onclick attribute in the markup
        // this is in case this may be causing some of the confirm errors we're getting  
        // wizardNext.onclick = nextLink.onclick;
    }
    /*function ReplicateNextLinkClick(source){
        // replicate clicking of the wizard next button by navigating  the href if the onclick function returns true
        var nextLink = $g(wizardNextID);
        var result = nextLink.onclick()
        if(result){ 
            source.style.display = 'none';
            document.location.href = nextLink.href;
        }
        return result;
    }*/
    function ShowCarousel(){
        var carouselDiv = $g('carouselDiv');
        // need to bind showCarousel to the window namespace as if it we just use showCarousel and
        // it doesn't exist at all then any function call with it will fail
        if(!isUndefined(window.showCarousel) && carouselDiv.style.display != window.showCarousel) 
            carouselDiv.style.display = window.showCarousel;
    }
    function ShowTotal(quantitySelect,unitPrice,tyreRebate){
        var additionalUnitPrice = 0;
        var totalPrice = quantitySelect.nextSibling.nextSibling;
        if(quantitySelect.selectedIndex > 0){
            var quantity = quantitySelect[quantitySelect.selectedIndex].text;
            var inclRebate = '';
	        var firstTyreTotal = Math.round(unitPrice * 100)/100;
            // 11-Jun-2010 - JB - rebate on 2nd and each tyre thereafter
            if(quantity >= 2){
                // unitPrice -= tyreRebate;
                additionalUnitPrice = firstTyreTotal - tyreRebate;
                
                if(tyreRebate > 0)
                    inclRebate = '(incl rebate)';
            } 
           
            // use Math.round to round to 2 decimal places
            // var total = String(Math.round((quantity * unitPrice) * 100)/100);
            var additionalTyresTotal = Math.round(((quantity - 1) * additionalUnitPrice) * 100)/100;
            var total = String(Math.round((firstTyreTotal + additionalTyresTotal) * 100)/100); 
            // add trailing '0' where trailing 0 has been truncated like 59.1 for example
            if(total.indexOf('.') == (total.length - 2)) total += '0';
            totalPrice.innerHTML = 'total&nbsp;' + inclRebate + '&nbsp;&pound;' + total;
        }
        else totalPrice.innerHTML = ''; 
    }
    function SetActiveMenu(menuName){
        var links = $$($g('nav'),'a');
        for(var i=0,link;link = links[i];i++){
            if(link.innerHTML == menuName){
                // set class name on parent li element
                link.parentNode.className = 'active';
            }
            else link.parentNode.className = '';        
        }
    }
    function SetTrailWizard(){
        var listItems = $$($g('steps'), 'li');
        var confirmation = 'Confirmation';
        var activeSet = false;
        var start = listItems.length - 1; // start from the end of the array
        for(var i = start;i >= 0;i--){
            listItem = listItems[i];
            if(listItem.id == wizardStep && listItem.id != confirmation){
                listItem.className = 'activeDone';
                if(i >= 1){
                    // set the previous step to 'done'
                    // pre-decrement (--i) substracts 1 from i and uses the new value as the array indexer 
                    listItems[--i].className = 'done';
                }
                activeSet = true;  
            } 
            else if(listItem.id == confirmation){
                if(listItem.id == wizardStep){
                    listItem.className = 'activeDonelast';
                    // set the previous step to 'done'
                    listItems[--i].className = 'done';
                    activeSet = true;
                }
                else 
                    listItem.className = 'last';
            }
            else{
                if(activeSet)
                    listItem.className = 'previous';
                else
                    listItem.className = 'default'; 
            }
        }
    }    
    function GetElementPosition(element) {
        var x = 0, y = 0;
        var userAgent = navigator.userAgent.toLowerCase();
        if (isMac || isChrome || isSafari) {
            while (element != null) {
                try {
                    x += element.offsetLeft;
                    y += element.offsetTop;
                    element = element.offsetParent;
                }
                catch (exception) {
                    return { x: 0, y: 0 };
                }
            }
        }
        else {
            while (element != null) {
                try {
                    x += element.offsetLeft - element.scrollLeft;
                    y += element.offsetTop - element.scrollTop;
                    element = element.offsetParent;
                }
                catch (exception) {
                    return { x: 0, y: 0 };
                }
            }
        }
        return { x: x, y: y };
    }
    function ShowFullImage(currentEl) {
        var locationAdjustment = 12;
        $g('imageContainer').style.display = 'none'; // hide until the image has loaded
        var currentImage = null;
        if (currentEl.tagName.toLowerCase() == 'img') // image click itself
            currentImage = currentEl;
        else  // click on div below image so traverse the hierachy up to the tbody element to get the current image
            currentImage = $$(currentEl.parentNode.parentNode,'img')[0];

        position = GetElementPosition(currentImage);
        var left = 0;
        var top = 0;

        left = position.x;
        top = position.y;
       
        var imageDisplay = $g('imageDisplay');
        
        var imageSrc = $$(currentImage.parentNode, 'input')[0].value;
        
        if(!isChrome && !isSafari){
            // display containing div only once the image has loaded, otherwise we'll see the previous
            // image momentarily before the new image has loaded
            imageDisplay.onload = function(){ShowImage(left,top);};
            imageDisplay.src = imageSrc;
        }
        else{
            // onload was not working consitently with Chrome or Safari
            imageDisplay.src = imageSrc;
            ShowImage(left,top); 
        }
        // we now use a different image file for the large image so get the path for this from the hidden input
        // $g('imageDisplay').src = currentImage.src;
    }
    function ShowImage(left,top){
        var container = $g('imageContainer');
        container.style.position = 'absolute';
        container.style.left = left + 'px';
        container.style.top = top + 'px';
        container.style.display = 'block';
    }
    function HideFullImage(){
        var container = $g('imageContainer');
        if(container != null)
            container.style.display = 'none';
    }
    function ShowPopupDiv(elementID,buttonID){
        var locationAdjust = 15;
        var elementToShow = $g(elementID);
        var button = $g(buttonID);
        
        position = GetElementPosition(button);
        var left = 0;
        var top = 0;

        left = position.x + document.body.scrollLeft;
        top = position.y + document.body.scrollTop;
        
        elementToShow.style.left = left + locationAdjust + 'px';
        elementToShow.style.top = top + locationAdjust + 'px';
        elementToShow.style.display = 'block';
    }
    // only allow one time slot to be selected at a time
    function UnCheckTimeSlotCheckBoxes(el) {
        if (el.checked) {
            // store the selected time slot in the hidden input
            $g(bookedTimeSlot).value = el.parentNode.previousSibling.innerHTML;
            var els = $g(timeSlotDiv).getElementsByTagName('input');
            for (var i = 0, currentEl; currentEl = els[i]; i++) {
                if (el.type=='checkbox' && el.id != currentEl.id && currentEl.checked) currentEl.checked = false;
            }
        }
        else // unchecked
            $g(bookedTimeSlot).value = '';
       
        $g(messageDateTime).innerHTML = '';
    }
    function Trim(inputStringTrim) {
        fixedTrim = '';
        lastCh = ' ';
        for (x = 0; x < inputStringTrim.length; x++) {
            ch = inputStringTrim.charAt(x);
            if ((ch != ' ') || (lastCh != ' ')) { fixedTrim += ch; }
            lastCh = ch;
        }
        if (fixedTrim.charAt(fixedTrim.length - 1) == ' ')
        { fixedTrim = fixedTrim.substring(0, fixedTrim.length - 1); }
        return fixedTrim
    }
    function SetFocusWithDelay(elemID){
        window.setTimeout(function(){$g(elemID).focus();}, 200);
    }
    // drag drop support
    function Engage(evt, element) {
        var source = evt.srcElement ? evt.srcElement : evt.target;
        if (source.className == 'controlBar') { // control bar only to initiate drag
            offsetX = evt.clientX - ((element.offsetLeft) ? element.offsetLeft : 0);
            offsetY = evt.clientY - ((element.offsetTop) ? element.offsetTop : 0);
            // element.style.cursor = 'move';
            dragFunction = function(evt) { DragIt(evt, element) };
            eventManager.EventSubscribe('mousemove', document, dragFunction, false);
            releaseFunction = function() { Release(element) };
            eventManager.EventSubscribe('mouseup', document, releaseFunction, false);
            if (evt.preventDefault) {
                evt.preventDefault(); // need to prevent default mousedown for FF which was causing drag to be not allowed
            }
        }
    }
    function DragIt(evt, element) {
        if (offsetX != null && offsetX >= 0 && offsetY != null) {
            element.style.left = (evt.clientX - offsetX) + 'px';
            element.style.top = (evt.clientY - offsetY) + 'px';
        }
        if (evt.preventDefault) {
            evt.preventDefault(); 
        }
        else { // the following line prevents IE from not allowing drag for whatever reason
            evt.returnValue = false;
        }
    }
    function Release(element) {
        offsetX = null;
        offsetY = null;
        eventManager.EventUnSubscribe('mousemove', document, dragFunction, false);
        eventManager.EventUnSubscribe('mouseup', document, releaseFunction, false);
    }
    // to fix strange Firefox issue where the previously selected width (but not the ratio etc) 
    // is being persisted when clicking the back button to get to Home.aspx
    // so re-set this to the default if are no ratio list items in the ratio select element 
    function SetDefaultWidth(){
        if($g(ratioID).options.length == 0){
            $g(widthID).selectedIndex = 0;
        }
    }
}

function Validation(){
    this.CheckQuantitySelection = CheckQuantitySelection;
    this.CheckMailFormat = CheckMailFormat;
    this.CheckStockSearchValues = CheckStockSearchValues;
    this.CheckSelectedDateAndTime = CheckSelectedDateAndTime;
    this.CheckCustomerDetails = CheckCustomerDetails;
    this.CheckMail = CheckMail;
    
    function CheckQuantitySelection(){
        var selectionMade = false;
        var sels = $$(document,'select');
        for (var i = 0,sel;sel = sels[i];i++){
            if (sel.options[0].text.toLowerCase() == 'none' && sel.selectedIndex != 0){
                selectionMade = true;
                break;
            }
        }
        if (!selectionMade)
            alert('Please select a quantity');

        return selectionMade;
    }
    function CheckMailFormat(eMail) {
        var customerDetailsMessage = $g('customerDetailsMessage');
        eMail.value = elementManager.Trim(eMail.value);
        if (eMail.value != '') {
            var reg = new RegExp(/^\S+@\S+\.\S+$g/);

            if (!(eMail.value.match(reg))) {
                customerDetailsMessage.innerHTML = 'Not a valid email format.<br>';
            }
            else {
                if (customerDetailsMessage.innerHTML.indexOf('valid') != -1)
                    customerDetailsMessage.innerHTML = '';
            }
        }
    }
    function CheckMail(emailAddressID,confirmMail) {
        var emailAddress = $g(emailAddressID);
        var customerDetailsMessage = $g('customerDetailsMessage');
        if (confirmMail.value != '' && confirmMail.value.toLowerCase() != emailAddress.value.toLowerCase()) {
            customerDetailsMessage.innerHTML = 'The confirmed email is not the same as the original.';
        }
        else {
            if (customerDetailsMessage.innerHTML.indexOf('confirmed') != -1)
                customerDetailsMessage.innerHTML = '';
        }
    }
    function CheckCustomerDetails(){
        var result = true;
        var customerDetailsMessage = $g('customerDetailsMessage');
        var inputs = $$(document,'input');
        for(var i=0,input;input = inputs[i];i++){
            if(input.className.indexOf('requiredInput') != -1 && input.value == ''){
                customerDetailsMessage.innerHTML = 'input required in fields with brown borders below';
                result = false;
                break;    
            }
        }
        if(result)
            customerDetailsMessage.innerHTML = '';
        
        return result;
    }
    function CheckStockSearchValues(widthID, ratioID, rimID, messageID, postCodeID,locationID,home) {
        var retValue = true;
        var message = '';
        
        if($g(widthID).selectedIndex == 0){
            message = 'please select a width'
            retValue = false;   
            
            if(home == 'home') 
                message = '';
        }
        
        if(retValue && $g(ratioID).selectedIndex == 0){
            message = 'please select a ratio';
            retValue = false;    
        }
        
        if(retValue && $g(rimID).selectedIndex == 0){
            message = 'please select a rim diameter';
            retValue = false;
        }
        if (retValue && $g(postCodeID).selectedIndex == 0 && $g(locationID).selectedIndex == 0) {
            message = "Please select a post code.&nbsp;&nbsp;Please ring us if it's not in the list below";
            retValue = false;
        }
        
        var messageEl = $g(messageID);
        messageEl.innerHTML = message;
        
        if(!retValue){
            messageEl.innerHTML = message;
            messageEl.style.display = 'block';
        }
        else
            messageEl.style.display = 'none';
        
        return retValue;
    }
    function CheckSelectedDateAndTime(){
        var result = false;
        result = $g(bookedTimeSlot).value != '' && $g(selDate).value != ''; 
        
        if(!result)
            $g(messageDateTime).innerHTML = 'please select a date and time slot';
        
        return result;
    }
}

function EventManager(){
    this.EventSubscribe = EventSubscribe;
    this.EventUnSubscribe = EventUnSubscribe;
    this.FireAjaxPostBack = FireAjaxPostBack;
    this.GotoTyreQuoteWithParams = GotoTyreQuoteWithParams;
    
    function EventSubscribe(eventName, element, functionCall, capturePhase){
        if(isIE){
            if(!capturePhase) element.attachEvent('on' + eventName, functionCall);
        }
        else element.addEventListener(eventName, functionCall, capturePhase ? capturePhase : false);
    }
    function EventUnSubscribe(eventName, element, functionCall, capturePhase){
        if(isIE){
            if(!capturePhase) element.detachEvent('on' + eventName, functionCall);
        }
        else element.removeEventListener(eventName, functionCall, capturePhase ? capturePhase : false);
    }
    function FireAjaxPostBack(source, command, panelID, additional){
        // $ as token separator
        var args = source + '$' + command + '$' + panelID + '$' + (!isUndefined(additional) ? additional : '');
        __doPostBack(panelID, args);
    }
    function GotoTyreQuoteWithParams(widthID, ratioID, rimID, speedID){
        var width = $g(widthID);
        var widthText = width[width.selectedIndex].text;
        var ratio = $g(ratioID);
        var ratioText = ratio[ratio.selectedIndex].text;
        var rim = $g(rimID);
        var rimText = rim[rim.selectedIndex].text;
        var speed = $g(speedID);
        var speedText = speed[speed.selectedIndex].text;
        
        document.location.href = '/TyreQuote.aspx?width=' + widthText + '&ratio=' + 
            ratioText + '&rim=' + rimText + '&speed=' + speedText; 
    }
}
function CalendarManager(){
    this.SetUpCalendar = SetUpCalendar;
    // WrapDateStatusHandler creates a function closure as per http://www.jibbering.com/faq/faq_notes/closures.html
    // this allows us to bind the value of mode to an execution context so that it is persisted. 
    // If we are to only call calendar.setDateStatusHandler(function(date, y, m, d, mode){return dateStatusHandler(date, y, m, d, mode);});
    // as per the commented line below then mode will always be undefined when the function is called.
    // So we bind the value of mode in the closure and take function call parameters at run time (date, y, m, d)  
    // Also WrapDateStatusHandler is in scope with dateStatusHandler as they share the same parent function 
    function WrapDateStatusHandler(mode){
        function DateStatusHandler(date, y, m, d){
            return dateStatusHandler(date, y, m, d, mode);
        }
        return DateStatusHandler;
    } 
    
    function SetUpCalendar(calendarDivID, mode, selDateID){
        if(!isUndefined(window.startDate)){
            var calendarDiv = $g(calendarDivID);
            // clear the content as calendar may already exist in the div
            calendarDiv.innerHTML = '';
            calendar = new Calendar(1, null, function(calendar,date){onSelect(calendar, date, mode, selDateID);});
            calendar.setDateFormat('%d-%b-%Y');
            calendar.setRange(startDate.getFullYear(), endDate.getFullYear());
            calendar.isPopup = false;
            calendar.create(calendarDiv);
            
            if(!isUndefined(window.freeDates)){
                calendar.setDateStatusHandler(WrapDateStatusHandler(mode));
                // calendar.setDateStatusHandler(function(date, y, m, d, mode){return dateStatusHandler(date, y, m, d, mode);});
            }

            calendar.refresh();
            var selectedDate = $g(selDateID).value;
            if(selectedDate != '') calendar.parseDate(selectedDate);
            calendar.show();
        }
    }
    
    function onSelect(calendar, date, mode, selDateID) {
        if (calendar.dateClicked) {
            $g(selDateID).value = ' ' + date;
            if (mode == 'edit') {
            /*    var updatePanelID = '';
                var bookingMode = $g(bookingModeID).value;

                switch (bookingMode) {
                    case 'Scheduled':
                        updatePanelID = 'BookingAdmin1_bookingPanel';
                        break;

                    case 'NonScheduled':
                        updatePanelID = 'BookingAdmin2_bookingPanel';
                        break;

                    case 'Service':
                        updatePanelID = 'BookingAdmin3_bookingPanel';
                        break;
                }
                FireAjaxPostBack('calendarBookingEdit', 'customerBooking', updatePanelID, date);*/
            }
            else if (mode == 'Navigate') {
                eventManager.FireAjaxPostBack('calendarNavigate', 'customerBooking', 'bookingPanel1', date);
            }
            else {
                // FireBookingPostBack('booking', 'booking');
                eventManager.FireAjaxPostBack('booking', 'booking', mainPanelID);
            }
        }
    }

    function dateStatusHandler(date, y, m, d, mode) {
        // return string for css class name for special formatting
        // date parameter has the current time so set a new Date variable below with no time value
        var dateNoTime = new Date(y, m, d);
        var noSelect = true;
        var cssClass = '';
        for (var i = 0, freeDate; freeDate = freeDates[i]; i++) {
             if(mode == 'Navigate') noSelect = false; // booking admin so can select any date
            // Date is a reference type object so need to compare the values with getTime
            // as testing equivalence on the different objects will fail even when their values are the same
            if (freeDate.date.getTime() == dateNoTime.getTime()) {
                if(mode == 'Navigate'){ // booking admin so need to show booked days
                    if (freeDate.areBookings) cssClass = 'areBookings';
                }
                else{
                    noSelect = false;
                }
                
                break;
            }
        }
        return cssClass != '' ? cssClass : noSelect;
    }
}

function CustomerDetailsManager(){
     this.ShowCustomerDetails = ShowCustomerDetails;
     this.ShowCustomerDetailsDiv = ShowCustomerDetailsDiv;
     this.CancelEdit = CancelEdit;
     this.CheckValues = CheckValues;
     
     function ShowCustomerDetails(element,bookingMode,bookingTime,vanName) {
        ShowCustomerDetailsDiv(element,'');
        
        if(document.body.scrollTop > 0)
            customerDetails.scrollIntoView();

        $g(firstNameID).focus();

        $g(bookingModeID).value = bookingMode;
        $g(vanNameID).value = vanName;

        if(bookingTime != '')
            $g(bookingTimeID).value = bookingTime;
    }
    function ShowCustomerDetailsDiv(element,mode,bookingMode) {
        var customerDetails = $g('customerDetails');
        if(element.tagName == 'IMG') // want to position relative to the parent div 
            element = element.parentNode;
        
        var pos = elementManager.GetElementPosition(element);
        var adjustX = 1
        var adjustY = 1;
        customerDetails.style.left = (pos.x + adjustX) + 'px';
        customerDetails.style.top = (pos.y + adjustY + document.body.scrollTop) + 'px';
        customerDetails.style.display = 'block';
          
        var editDiv = $g('editMode');  
        // 'edit' mode or may have clicked '+' icon while in edit mode
        // so editDiv may be showing but mode variable passed in is not 'edit'     
        if(mode == 'edit' || editDiv.style.display == 'block') {
            editDiv.style.display = 'block';
            if(document.body.scrollTop > 0)
                editDiv.style.top = document.body.scrollTop+ 5 + 'px';
            else
                editDiv.style.top = '3px';
        }
        else ClearValues();
    }
    function CancelEdit() {
        ClearValues();
        // hide the 'edit mode' div
        $g('editMode').style.display = 'none';
        eventManager.FireAjaxPostBack('editCancel','editCancel','calendarAndDetails');
    }
    function ClearValues(){
        $g(firstNameID).value = '';
        $g(lastNameID).value = '';
        $g(phoneID).value = '';
        $g(emailID).value = '';
        $g(regID).value = '';
        $g(address1ID).value = '';
        $g(address2ID).value = '';
        $g(postCodeID).value = '';
    }
    function CheckValues() {
        var result = ($g(firstNameID).value !='' && $g(lastNameID).value != '' && $g(phoneID).value!= '');

        if(!result)
            alert('first name, last name and phone are required');
        else {
            /* we have to invoke the ajax post on the appropriate user control so that the content
            in this user control can be updated. This customer details user control is not in the same update panel
            as it's shared amongst the 3 scheduler user controls */
            var updatePanelID = 'bookingPanel1';
            var bookingMode = $g(bookingModeID).value;

            eventManager.FireAjaxPostBack('customerBooking','customerBooking',updatePanelID);
            $g('customerDetails').style.display = 'none';
            $g('editMode').style.display = 'none';
        }
        return false;
    }
}
