
function TemplatePreviewManager(SelectPhotos, PhotoEditTab, TemplatePanel, AddPhotosPanel)
{
    this.selectPhotos = photoEditTab.getSelectPhotoPanel();
    this.photoEditTab = PhotoEditTab;
    this.templatePanel = TemplatePanel;
    this.addPhotosPanel = AddPhotosPanel;
    
    this.selectPhotos.setManager(this);
    this.photoEditTab.setManager(this);
    this.templatePanel.setManager(this);
    this.addPhotosPanel.setManager(this);
    
    this.selectPhotos.SetClientDragMouseMoveCallback(this.OnMediaDragMouseMove);
    this.selectPhotos.SetClientDragMouseUpCallback(this.OnMediaDragMouseUp);
    this.templatePanel.setOnActiveApertureChangedCallback(this.OnActiveApertureChanged);
    
    if (this.templatePanel.getOptions().virtualApertureIDs == false)
    {
        this.templatePanel.getTemplateOptions().setTemplateOptionChangedCallback(this, this.setViewByTemplateIDPreserveApertures);
    }
    else
    {
        this.templatePanel.getTemplateOptions().setTemplateOptionChangedCallback(this, this.setViewByTemplateIDReplaceApertures);
    }
    
    this.photoEditTab.setMediaReloadCallback(this.OnMediaReload);
    this.photoEditTab.setMediaNotifyCallback(this.OnMediaOperation);
    this.photoEditTab.setZoomChangedCallback(this.OnZoomChanged);
    this.photoEditTab.setZoomChangedNoApertureCallback(this.OnZoomChangedNoAperture);
    
    if (this.addPhotosPanel.setAlbumChangedCallback)
    {
        this.addPhotosPanel.setAlbumChangedCallback(this.OnAlbumChanged);       // old AddPhotosTab
    }
    else
    {
        this.addPhotosPanel.setOnAlbumChangedCallback(this.OnAlbumChanged);     // new TabsPanel
    }
    
    this.service = new IGiftService();
    
    // init
    
    var defaultAperture = this.templatePanel.getActiveOrDefaultAperture();
    
    if (defaultAperture != null)
    {
        this.photoEditTab.setApertureID(defaultAperture.getApertureID());
        this.photoEditTab.setMediaID(defaultAperture.getMediaID());
        this.photoEditTab.setZoomLevel(defaultAperture.getZoomLevel());
    }
}

TemplatePreviewManager.prototype = {

    selectPhotos: null,
    photoEditTab: null,
    templatePanel: null,
    addPhotosPanel: null,
    service: null,
    mediaAddedToApertureCallback: null,
    mediaMustBeDroppedOverAperture: true,
    onViewChangedCallback: null,
    
    getManager: function()
    {
        return this;
    },
    
    setOnViewChangedCallback: function(func)
    {
        this.onViewChangedCallback = func;
    },
    
    setMediaMustBeDroppedOverAperture: function(enable)
    {
        this.mediaMustBeDroppedOverAperture = enable;
    },
    
    setMediaAddedToApertureCallback: function(func)
    {
        this.mediaAddedToApertureCallback = func;
    },
    
    preloadApertures: function()
    {
        var aperture = this.templatePanel.getActiveOrDefaultAperture();     // TODO: preload all empty apertures...
        var media = this.selectPhotos.GetSelectedMedia();
        
        if (aperture != null && media != null && aperture.getMediaID() == null)
        {
            this.AddMediaToAperture(aperture, media);
        }
    },
    
    OnAlbumChanged: function(album)
    {
        this.getManager().selectPhotos.SetAlbumID(album.EncID ? album.EncID : album.ID);
    },
    
    OnMediaAddedToAperture: function(aperture, media)
    {
        if (this.mediaAddedToApertureCallback != null)
        {
            this.mediaAddedToApertureCallback(aperture, media);
        }
    },
    
    OnMediaDragMouseUp: function(media, position)
    {
        var photoEditTab = this.getManager().photoEditTab;
        var templatePanel = this.getManager().templatePanel;
        
        var aperture = templatePanel.getApertureRegionByPosition(position);
        
        if (aperture == null && this.getManager().mediaMustBeDroppedOverAperture == false)
        {
            aperture = templatePanel.getActiveOrDefaultAperture();
        }
        
        if (aperture != null)
        {
            this.getManager().AddMediaToAperture(aperture, media);
        }
    },
    
    AddMediaToAperture: function(aperture, media)
    {
        this.photoEditTab.setApertureID(aperture.getApertureID());
        this.photoEditTab.setZoomLevel(aperture.getZoomLevel());
        
        var oldMediaID = aperture.getMediaID();
        
        if (oldMediaID != null)
        {
            this.photoEditTab.setMediaID(oldMediaID);
            this.photoEditTab.clearSessionEdits();
        }
        
        this.photoEditTab.setMediaID(media.ID);
        this.photoEditTab.selectTintRadioButton(media.tint);
        this.photoEditTab.setZoomLevel(0);
        
        aperture.addMedia(media.ID, media.ThumbURL, media.width, media.height);
        
        this.OnMediaReload(media.PreviewURL, 'load');
        this.OnMediaAddedToAperture(aperture, media);
        
        this.templatePanel.evalResolutionWarning();
        
        this.photoEditTab.processRequirements();
    },
    
    OnMediaDragMouseMove: function(media, position)
    {
        var templatePanel = this.getManager().templatePanel;
        
        var aperture = templatePanel.getApertureRegionByPosition(position);
        
        if (aperture != null)
        {
            aperture.focus();
        }
        else
        {
            templatePanel.blurActiveAperture();
        }
    },
    
    OnActiveApertureChanged: function(aperture)
    {
        if (aperture == null)
        {
            return;
        }
        
        var photoEditTab = this.getManager().photoEditTab;
        
        photoEditTab.setApertureID(aperture.getApertureID());
        photoEditTab.setMediaID(aperture.getMediaID());
        photoEditTab.setZoomLevel(aperture.getZoomLevel());
        
        var tint = aperture.getMediaParam('tint');
        
        if (tint != 'undefined' && tint != null)
        {
            photoEditTab.selectTintRadioButton(tint);
        }
        else
        {
            photoEditTab.selectTintRadioButton(0);
        }
    },
    
    OnMediaOperation: function(type)
    {
        var apertureID = this.getManager().photoEditTab.getApertureID();
        var mediaID = this.getManager().photoEditTab.getMediaID();
        
        if (apertureID == null || mediaID == null)
        {
            this.getManager().alertNoMediaInAperture();
            return false;
        }
        else
        {
            if (type == 'tint')
            {
                var aperture = this.getManager().templatePanel.getApertureByID(apertureID);
                aperture.setMediaParam('tint', this.getManager().photoEditTab.getCurrentTint());
            }
            
            showLoadingPopupDelayed();
            return true;
        }
    },
    
    OnMediaReload: function(url, opType)
    {
        ImageLoader.Load(url, OnMediaReloadImageLoaded, 
            { opType: opType,
              mediaID: this.photoEditTab.getMediaID(),
              apertureID: this.photoEditTab.getApertureID(),
              editFrame: this.photoEditTab.getFrame(),
              manager: this }
         );
    },
    
    OnZoomChanged: function(zoomLevel)
    {
        var templatePanel = this.getManager().templatePanel;
        var aperture = templatePanel.getActiveOrDefaultAperture();
        aperture.setZoomLevel(zoomLevel);
        templatePanel.evalResolutionWarning();
    },
    
    OnZoomChangedNoAperture: function()
    {
        this.getManager().alertNoMediaInAperture();
    },
    
    alertNoMediaInAperture: function()
    {
        if (typeof(msgBox) != 'undefined')
        {
            msgBox.Show(res_Warning, res_NoImageInApertureMsg, [ { Button: 'OK' } ]);
        }
        else
        {
            alert(res_NoImageInApertureMsg);
        }
    },
    
    getActiveAperture: function()
    {
        return this.templatePanel.getActiveAperture();
    },
    
    setViewByIndex: function(index)
    {
        this.templatePanel.setViewByIndex(index);
        this.OnActiveApertureChanged(this.templatePanel.getActiveOrDefaultAperture());
    },
    
    setViewByApertureID: function(apertureID)
    {
        this.templatePanel.setViewByApertureID(apertureID);
        this.OnActiveApertureChanged(this.templatePanel.getActiveOrDefaultAperture());
    },
    
    getCurrentViewIndex: function()
    {
        return this.templatePanel.getCurrentViewIndex();
    },
    
    allAperturesHaveImagesInCurrentView: function()
    {
        var view = this.templatePanel.getCurrentView();
        
        if (view == null)
        {
            return true; // ?
        }
        
        var apertureCount = view.getApertureCount();
        
        for (var i = 0; i < apertureCount; i++)
        {
            var ap = view.getApertureByIndex(i);
            var mid = ap.getMediaID();
            
            if (mid == null || mid.length == 0)
            {
                return false;
            }
        }
    
        return true;
    },
    
    //
    // Must be using Virtual Aperture ID's (enable them on templatePanel, otherwise session state is out of sync)
    //
    setViewByTemplateIDReplaceApertures: function(templateID, optionValues)
    {
        var index = this.templatePanel.getViewIndexByTemplateID(templateID);
        this.setViewByIndexReplaceApertures(index);
        this.templatePanel.buildLayers();
    },
    
    setViewByTemplateIDPreserveApertures: function(templateID, optionValues)
    {
        var index = this.templatePanel.getViewIndexByTemplateID(templateID);
        this.setViewByIndexPreserveApertures(index);
        this.templatePanel.buildLayers();
    },
    
    setViewByIndexPreserveOrReplaceApertures: function(index)
    {
        if (this.templatePanel.getOptions().virtualApertureIDs == false)
        {
            this.setViewByIndexPreserveApertures(index);
        }
        else
        {
            this.setViewByIndexReplaceApertures(index);
        }
    },
    
    setViewByIndexReplaceApertures: function(index)
    {
        var view = this.templatePanel.getCurrentView();
        var media = new Array;
        
        for (var i = 0; i < view.getApertureCount(); i++)
        {
            var aperture = view.getApertureByIndex(i);
            
            if (aperture.getMediaID() != null)
            {
                media.push(aperture.getMediaInfo());
            }
            else
            {
                media.push(null);
            }
        }
        
        this.templatePanel.setViewByIndex(index);
        view = this.templatePanel.getCurrentView();
        
        for (var i = 0; i < view.getApertureCount(); i++)
        {
            var aperture = view.getApertureByIndex(i);
            
            if (media[i] != null)
            {
                aperture.addMediaFromMediaInfo(media[i]);
            }
        }
        
        this.OnActiveApertureChanged(this.templatePanel.getActiveOrDefaultAperture());
        
        if (this.onViewChangedCallback != null)
        {
            this.onViewChangedCallback();
        }
    },
    
    setViewByIndexPreserveApertures: function(index)
    {
        var view = this.templatePanel.getCurrentView();
        var media = new Array;
        
        for (var i = 0; i < view.getApertureCount(); i++)
        {
            media.push(view.getApertureByIndex(i).getMediaInfo());
        }
        
        this.templatePanel.setViewByIndex(index);
        view = this.templatePanel.getCurrentView();
        
        for (var i = 0; i < view.getApertureCount(); i++)
        {
            var aperture = view.getApertureByIndex(i);
            
            if (aperture.getMediaID() == null && i < media.length && media[i].ID != null)
            {
                var sMedia = this.selectPhotos.GetMediaByID(media[i].ID);
                aperture.addMedia(sMedia.ID, sMedia.PreviewURL, sMedia.width, sMedia.height);
            }
        }
        
        this.OnActiveApertureChanged(this.templatePanel.getActiveOrDefaultAperture());
        
        if (this.onViewChangedCallback != null)
        {
            this.onViewChangedCallback();
        }
    },
    
    saveTemplateInfo: function(callback)
    {
        var saveInfo = this.templatePanel.getSaveInfo();
        this.service.SaveGiftFlowInfo(saveInfo, callback);
    }
    
};

//
// This does not work in the above prototype (image onload is never called when set to 'this.something()')
//
function OnMediaReloadImageLoaded(context)
{
    hideLoadingPopup();
    
    var aperture = context.manager.templatePanel.getApertureByID(context.apertureID);
    
    if (aperture == null || aperture.getMediaID() != context.mediaID || context.editFrame != context.manager.photoEditTab.getFrame())
    {
        return;
    }
    
    if (context.opType == 'rotate')
    {
        aperture.rotateMedia(this.src);
    }
    else
    {
        aperture.updateMedia(this.src);
    }
}


//
// Common code - move to common.js
//

function getMousePositionFromRawEvent(e)
{
    var x = 0;
    var y = 0;
    if (e.pageX || e.pageY)
    {
        x = e.pageX;
        y = e.pageY;
    }
    else if (e.clientX || e.clientY)
    {
        x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
        y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
    }
    return { x: x, y: y };
}

//
// Template Panel Options
//

function TemplatePanelOptions()
{
}

TemplatePanelOptions.prototype = {
    
    apertureBorderWidth:4,
    apertureBorderColor:'orange',
    zoomFactor: 1.1,
    editable: true,
    virtualApertureIDs: false,
    defaultApertureImageUrl: '/images/album/cards/default_text_h.gif'
};

//
// Template Panel
//

function TemplatePanel()
{
    this.views = new Array();
    this.overlayLayers = new Array();
    this.overlayLayerValue = new Array();
}

TemplatePanel.prototype = {

    rpID: null,
    views: null,
    overlayLayers: null,
    overlayLayerValue: null,
    currentViewIndex: 0,
    panelContainerID: null,
    options:null,
    templateOptions:null,
    mouseDownHandler:null,
    mouseMoveHandler:null,
    onActiveApertureChangedCallback:null,
    resolutionWarningDivId:null,
    priceDivId:null,
    manager:null,

    setManager: function(manager)
    {
        this.manager = manager;
    },

    getManager: function()
    {
        return this.manager;
    },

    setOnActiveApertureChangedCallback: function(func)
    {
        this.onActiveApertureChangedCallback = func;
    },
    
    setResolutionWarningDivId: function(id)
    {
        this.resolutionWarningDivId = id;
    },

    setPriceDivId: function(id)
    {
        this.priceDivId = id;
    },

    onActiveApertureChanged: function(aperture)
    {
        if (this.onActiveApertureChangedCallback != null)
        {
            this.onActiveApertureChangedCallback(aperture);
        }
    },

    addView: function(view)
    {
        view.setParent(this);
        view.setOnActiveApertureChangedCallback(this.onActiveApertureChanged);
        
        this.views.push(view);
    },
    
    addLayer: function()
    {
        this.overlayLayers.push(new Array());
        this.overlayLayerValue.push(null);
    },
    
    addLayerOptions: function(index, options)
    {
        this.overlayLayers[index].push(options);
    },
    
    setViewByApertureID: function(apertureID)
    {        
        for (var i = 0; i < this.views.length; i++)
        {
            var aperture = this.views[i].getApertureByID(apertureID);
            
            if (aperture != null)
            {
                this.setViewByIndex(i);
                break;
            }
        }
    },
    
    setInitialViewByID: function(id)
    {
        for (var i = 0; i < this.views.length; i++)
        {
            if (this.views[i].id == id)
            {
                this.currentViewIndex = i;
                break;
            }
        }
    },
    
    setViewByTemplateID: function(id)
    {
        for (var i = 0; i < this.views.length; i++)
        {
            if (this.views[i].templateID == id)
            {
                this.setViewByIndex(i);
                this.render();
                break;
            }
        }
    },
    
    getViewIndexByTemplateID: function(id)
    {
        for (var i = 0; i < this.views.length; i++)
        {
            if (this.views[i].templateID == id)
            {
                return i;
            }
        }
        return -1;
    },
    
    setViewByID: function(id)
    {
        for (var i = 0; i < this.views.length; i++)
        {
            if (this.views[i].id == id)
            {
                this.setViewByIndex(i);
                this.render();
                break;
            }
        }
    },
    
    getViewByIndex: function(index)
    {
        return this.views[index];
    },
    
    getViewCount: function()
    {
        return this.views.length;
    },
    
    setViewByIndex: function(index)
    {
        if (this.currentViewIndex != index)
        {
            this.views[this.currentViewIndex].saveRenderState();            
            this.blurActiveAperture();
            this.currentViewIndex = index;
            this.render();
        }
        this.update();
    },
    
    getCurrentView: function()
    {
        return this.views[this.currentViewIndex];
    },
    
    getCurrentViewIndex: function()
    {
        return this.currentViewIndex;
    },
    
    setOptions: function(options)
    {
        this.options = options;
    },
    
    getOptions: function()
    {
        return this.options;
    },
    
    setTemplateOptions: function(templateOptions)
    {
        this.templateOptions = templateOptions;
    },
    
    getTemplateOptions: function()
    {
        return this.templateOptions;
    },
    
    getApertureRegionByPosition: function(position)
    {
        return this.views[this.currentViewIndex].getApertureRegionByPosition(position);
    },
    
    getApertureByID: function(ID)
    {
        return this.views[this.currentViewIndex].getApertureByID(ID);
    },
    
    getActiveAperture: function()
    {
        return this.views[this.currentViewIndex].getActiveAperture();
    },
    
    getActiveOrDefaultAperture: function()
    {
        return this.views[this.currentViewIndex].getActiveOrDefaultAperture();
    },
    
    blurActiveAperture: function()
    {
        this.views[this.currentViewIndex].blurActiveAperture();
    },
    
    init: function(rpID)
    {
        this.rpID = rpID;
        
        var container = document.getElementById(this.panelContainerID);
        
        $clearHandlers(container);
        
        if (this.options.editable)
        {
            this.mouseDownHandler = Function.createDelegate(this, this.onMouseDown);
            this.mouseMoveHandler = Function.createDelegate(this, this.onMouseMove);
            
            $addHandler(container, 'mousedown', this.mouseDownHandler);
            $addHandler(container, 'mousemove', this.mouseMoveHandler);
        }
    },
    
    render: function()
    {
        var container = document.getElementById(this.panelContainerID);
        
        var child = container.childNodes[0];
        
        while (child)
        {
            container.removeChild(container.childNodes[0]);
            child = container.childNodes[0];
        }
        
        if (this.views != null && this.views.length > 0)
        {
            this.views[this.currentViewIndex].render(container, this.options);
        }
        
        if (BrowserIsIE6())
        {
            ie_png_fix_limit(this.panelContainerID);
        }
    },
    
    setOverlayLayerOption: function(index, option)
    {
        this.overlayLayerValue[index] = option;
    },

    setLayerProductOptions: function(index, options)
    {
        this.setOverlayLayerOption(index, options[0]);      // only using first option for now (for custom framing)
    },

    buildLayers: function()
    {
        this.buildLayersFromOptions(this.templateOptions.getOptionValues());
    },
    
    buildLayersFromOptions: function(options)
    {
        for (var i = 0; i < this.overlayLayers.length; i++)
        {
            var overlayLayerOptions = this.overlayLayers[i];
            var specific_option = this.overlayLayerValue[i];
            
            var compareOptions = new Array();

            //for (var k = 0; k < options.length; k++)
            //{
            //    compareOptions.push(options[k]);
            //}
            
            compareOptions.push(options[0]);
            compareOptions.push(options[2]);
        
            if (specific_option !== null)
            {
                compareOptions.push(specific_option);
            }
            
            for (var j = 0; j < overlayLayerOptions.length; j++)
            {
                var option = overlayLayerOptions[j];
                var layerFound = true;

                for (var n = 0; n < compareOptions.length; n++)
                {
                    var optionFound = false;
                    
                    for (var m = 0; m < option.Options.length; m++)
                    {
                        if (option.Options[m] == compareOptions[n])
                        {
                            optionFound = true;
                            break;
                        }
                    }
                    
                    if (optionFound == false)
                    {
                        layerFound = false;
                        break;
                    }
                }

                if (layerFound)
                {
                    this.views[this.currentViewIndex].renderOverlay(option.OverlayURL);
                    break;
                }
            }
        }
        
        if (BrowserIsIE6())
        {
            ie_png_fix_limit(this.panelContainerID);
        }
    },
    
    update: function()
    {
        if (this.priceDivId != null)
        {
            var priceDiv = document.getElementById(this.priceDivId);
            
            if (priceDiv != null)
            {
                var price = this.getTemplateOptions().getPrice();
                
                if (price > 0)
                {
                    priceDiv.innerHTML = '&pound;' + price.toFixed(2);
                }
            }
        }
    },
    
    onMouseDown: function(event)
    {
        var position = getMousePositionFromRawEvent(event.rawEvent);
        var aperture = this.getApertureRegionByPosition(position);
        
        if (aperture != null)
        {
            aperture.focus();
            aperture.onMouseDown(event);
            
            if (this.onActiveApertureChanged != null)
            {
                this.onActiveApertureChanged(aperture);
            }
        }
        else
        {
            this.blurActiveAperture();
        }
    },
    
    onMouseMove: function(event)
    {
        var container = document.getElementById(this.panelContainerID);
        var position = getMousePositionFromRawEvent(event.rawEvent);
        var active = this.getActiveAperture();
        
        if (active != null && active.isDragging())
        {
            container.style.cursor = 'move';
        }
        else
        {
            var aperture = this.getApertureRegionByPosition(position);
            container.style.cursor = aperture != null ? 'pointer' : 'default';
        }
    },
    
    getSaveInfo: function()
    {
        if (this.views != null)
        {
            var result =
            {
                RetailerProductID: this.rpID,
                SelectedView: this.views[this.currentViewIndex].id,
                ViewSaveInfo: new Array,
                OrderItemOptions: this.templateOptions.getSaveInfo()
            };
            
            for (var i = 0; i < this.views.length; i++)
            {
                var info = this.views[i].getSaveInfo();
                result.ViewSaveInfo.push(info);
            }
        
            return result;
        }
        else
        {
            return { RetailerProductID: this.rpID };
        }
    },
    
    evalResolutionWarning: function()
    {
        if (this.views == null || this.views.length == 0)
        {
            return false;
        }
        
        var result = this.views[this.currentViewIndex].evalResolutionWarning();
        
        if (this.resolutionWarningDivId != null)
        {
            var div = document.getElementById(this.resolutionWarningDivId);
            
            if (div != null)
            {
                div.style.display = result ? '' : 'none';
            }
        }
    
        return result;
    }

};

//
// Template View (Orientation)
//

function TemplateView(ID, type, templateID, Width, Height, OverlayURL)
{
    this.id = ID;
    this.type = type;
    this.templateID = templateID;
    this.width = Width;
    this.height = Height;
    var overlayUrl = "";
    if (OverlayURL != null && typeof OverlayURL != "undefined")
        overlayUrl = OverlayURL.replace( /^\s*/, "" ).replace("../", "/").replace("./", "/");
    this.overlayURL = overlayUrl;
    this.apertureRegions = new Array;
}

TemplateView.prototype = {

    width:0,
    height:0,
    overlayURL:null,
    apertureRegions:null,
    textRegions:null,
    id:null,
    parent:null,
    rendered:false,
    onActiveApertureChangedCallback: null,
    domContent: null,
    
    setParent: function(owner)
    {
        this.parent = owner;
    },
    
    addAperture: function(aperture)
    {
        this.apertureRegions.push(aperture);
        
        aperture.init(this, this.apertureRegions.length - 1);
        aperture.onFocusCallback = this.onActiveApertureChanged;
    },
    
    onActiveApertureChanged: function(aperture)
    {
        if (this.onActiveApertureChangedCallback != null)
        {
            this.onActiveApertureChangedCallback(aperture);
        }
    },
    
    setOnActiveApertureChangedCallback: function(func)
    {
        this.onActiveApertureChangedCallback = func;
    },
    
    getApertureRegionByPosition: function(position)
    {
        for (var i = 0; i < this.apertureRegions.length; i++)
        {
            var bounds = Sys.UI.DomElement.getBounds(this.apertureRegions[i].context.regionDiv);
            
            if ((position.x >= bounds.x) && (position.x < (bounds.x + bounds.width)) && (position.y >= bounds.y) && (position.y < (bounds.y + bounds.height)))
            {
                return this.apertureRegions[i];
            }
        }
        return null;
    },
    
    getActiveAperture: function()
    {
        for (var i = 0; i < this.apertureRegions.length; i++)
        {
            if (this.apertureRegions[i].hasFocus())
            {
                return this.apertureRegions[i];
            }
        }
        return null;
    },
    
    getActiveOrDefaultAperture: function()
    {
        var active = this.getActiveAperture();
        
        if (active == null)
        {
            if (this.apertureRegions.length > 0)
            {
                return this.apertureRegions[0];
            }
            else
            {
                return null;
            }
        }
        else
        {
            return active;
        }
    },
    
    getApertureByIndex: function(index)
    {
        return this.apertureRegions[index];
    },
    
    getApertureCount: function()
    {
        return this.apertureRegions.length;
    },
    
    getApertureByID: function(ID)
    {
        for (var i = 0; i < this.apertureRegions.length; i++)
        {
            if (this.apertureRegions[i].getApertureID() == ID)
            {
                return this.apertureRegions[i];
            }
        }
        return null;
    },
    
    setApertureFocusByID: function(apertureID)
    {
        for (var i = 0; i < this.apertureRegions.length; i++)
        {
            if (this.apertureRegions[i].getApertureID() == apertureID)
            {
                this.apertureRegions[i].focus();
            }
            else
            {
                this.apertureRegions[i].blur();
            }
        }
    },
    
    setApertureFocusByIndex: function(index)
    {
        for (var i = 0; i < this.apertureRegions.length; i++)
        {
            if (i == index)
            {
                this.apertureRegions[i].focus();
            }
            else
            {
                this.apertureRegions[i].blur();
            }
        }
    },
    
    blurActiveAperture: function()
    {
        for (var i = 0; i < this.apertureRegions.length; i++)
        {
            this.apertureRegions[i].blur();
        }
    },
    
    saveRenderState: function()
    {
        if (this.rendered)
        {
            if (this.apertureRegions != null)
            {
                for (i = 0; i < this.apertureRegions.length; i++)
                {
                    this.apertureRegions[i].saveRenderState();
                }
            }
            this.rendered = false;
        }
    },
    
    render: function(parent, options)
    {
        var i;
        var content = document.createElement("div");
        
        this.domContent = content;
        
        content.style.width = this.width + 'px';
        content.style.height = this.height + 'px';
        content.style.position = 'relative';
        content.style.textAlign = 'left';
        
        if (this.apertureRegions != null)
        {
            for (i = 0; i < this.apertureRegions.length; i++)
            {
                this.apertureRegions[i].render(content, options);
            }
        }
        
        if (this.textRegions != null)
        {
            for (i = 0; i < this.textRegions.length; i++)
            {
                this.textRegions[i].render(content, options);
            }
        }
        
        var overlay = document.createElement('img');
        overlay.src = this.overlayURL;
        overlay.style.position = 'absolute';
        overlay.style.left = '0';
        overlay.style.top = '0';
        overlay.style.width = this.width + 'px';
        overlay.style.height = this.height + 'px';
        
        content.appendChild(overlay);
        
        parent.appendChild(content);
        
        this.rendered = true;
    },
    
    renderOverlay: function(overlayURL)
    {
        var overlay = document.createElement('img');
        overlay.src = overlayURL;
        overlay.style.position = 'absolute';
        overlay.style.left = '0';
        overlay.style.top = '0';
        overlay.style.width = this.width + 'px';
        overlay.style.height = this.height + 'px';
        this.domContent.appendChild(overlay);
    },
    
    getSaveInfo: function()
    {
        var result = 
        {
            ID: this.id,
            Type: this.type,
            TemplateID: this.templateID,
            Apertures: new Array
        }
        
        for (var i = 0; i < this.apertureRegions.length; i++)
        {
            var info = this.apertureRegions[i].getSaveInfo();
            result.Apertures.push(info);
        }
        
        return result;
    },
    
    evalResolutionWarning: function()
    {
        for (var i = 0; i < this.apertureRegions.length; i++)
        {
            if (this.apertureRegions[i].evalResolutionWarning())
            {
                return true;
            }
        }
        return false;
    }

};

//
// Template Aperture Region
//

function TemplateApertureRegion(ID, Top, Left, Right, Bottom, MinRes)
{
    this.ID = ID;
    this.top = Top;
    this.left = Left;
    this.width = Right - Left;
    this.height = Bottom - Top;
    this.minRecommendedSize = MinRes;
    
    this.init(null);
};

TemplateApertureRegion.prototype = {

    ID: 0,
    top: 0,
    left: 0,
    width: 0,
    height: 0,
    minRecommendedSize: 0,
    context: null,
    cropInfo: null,
    rendered: false,
    borderWidth: 0,
    borderColor: null,
    parentView: null,
    borderVisible: false,
    media: null,
    mouseMoveHandler: null,
    mouseUpHandler: null,
    virtualApertureID: false,
    index: -1,

    dragging: false,
    dragPosition: null,
    dragImagePosition: null,

    onFocusCallback: null,
    onBlurCallback: null,

    zoomFactor: 1.1,         // set from options on render

    init: function(owner, index) {
        this.parentView = owner;
        this.index = index;

        if (this.context == null) {
            this.context = { regionDiv: null, borderDiv: null, baseImage: null, regionImage: null };
        }

        if (this.media == null) {
            this.media = { ID: null, width: 0, height: 0, URL: null, Params: new Object() };
        }

        if (this.mouseMoveHandler == null) {
            this.mouseMoveHandler = Function.createDelegate(this, this.onMouseMove);
        }

        if (this.mouseUpHandler == null) {
            this.mouseUpHandler = Function.createDelegate(this, this.onMouseUp);
        }
    },

    isDragging: function() {
        return this.dragging;
    },

    getApertureID: function() {
        if (this.virtualApertureID != true) {
            return this.ID;
        }
        else {
            return this.index;
        }
    },

    getApertureIndex: function() {
        return this.index;
    },

    //
    // Media
    //

    getMediaID: function() {
        return this.media.ID;
    },

    hasMedia: function() {
        return this.media.ID != null && this.media.ID.length > 0;
    },

    setMediaParam: function(name, value) {
        this.media.Params[name] = value;
    },

    getMediaParam: function(name) {
        return this.media.Params[name];
    },

    //
    // Rendering
    //

    saveRenderState: function() {
        this.cropInfo = this.getCropInfo();
        this.rendered = false;
    },

    render: function(parent, options) {
        this.zoomFactor = options.zoomFactor;

        this.renderBaseImage(parent, options);
        this.renderBorderDiv(parent, options);
        this.renderRegionDiv(parent, options);

        this.rendered = true;

        if (this.media != null && this.media.ID != null) {
            this.addMedia(this.media.ID, this.media.URL, this.media.width, this.media.height, this.media.tint);
        }

        if (this.cropInfo != null) {
            this.setCropInfo(this.cropInfo);
        }

        if (options.virtualApertureIDs == true) {
            this.virtualApertureID = true;
        }
    },

    renderBaseImage: function(parent, options) {
        var img = document.createElement('img');
        var sq = 15;
        img.id = 'aperture_base_' + this.ID;
        var imageUrl = "";
        if (options.defaultApertureImageUrl != null && typeof options.defaultApertureImageUrl != "undefined")
            imageUrl = options.defaultApertureImageUrl.replace("../", "/").replace("./", "/");
        img.src = imageUrl;
        img.style.position = 'absolute';
        img.style.left = (parseInt(this.left) + parseInt(this.width / 2) - sq) + 'px';
        img.style.top = (parseInt(this.top) + parseInt(this.height / 2) - sq) + 'px';

        this.context.baseImage = img;
        parent.appendChild(img);
    },

    renderBorderDiv: function(parent, options) {
        this.borderWidth = options.apertureBorderWidth;
        this.borderColor = options.apertureBorderColor;

        var borderDiv = document.createElement('div');
        this.setupDivPosition(borderDiv, this.borderWidth * 2, this.borderWidth * 2);
        borderDiv.style.zIndex = 100;
        borderDiv.style.cursor = 'pointer';

        this.context.borderDiv = borderDiv;

        // parent.appendChild(borderDiv);
    },

    setupDivPosition: function(div, offsetWidth, offsetHeight) {
        div.style.position = 'absolute';
        div.style.left = parseInt(this.left) + 'px';
        div.style.top = parseInt(this.top) + 'px';
        div.style.width = parseInt(this.width - offsetWidth) + 'px';
        div.style.height = parseInt(this.height - offsetHeight) + 'px';
    },

    renderRegionDiv: function(parent, options) {
        var regionDiv = document.createElement("div");
        this.setupDivPosition(regionDiv, 0, 0);
        regionDiv.style.overflow = 'hidden';

        var img = document.createElement('img');
        img.id = 'aperture_media_' + this.ID;
        img.style.position = 'absolute';
        img.src = '/images/spacer.gif';

        this.context.regionDiv = regionDiv;
        this.context.regionImage = img;

        regionDiv.appendChild(img);

        parent.appendChild(regionDiv);
    },

    //
    // Focus / Blur
    //

    hasFocus: function() {
        return this.borderVisible;
    },

    focus: function() {
        if (this.borderVisible == false) {
            this.parentView.blurActiveAperture();
            this.context.borderDiv.style.border = this.borderWidth + 'px solid ' + this.borderColor;
            this.borderVisible = true;

            if (this.onFocusCallback != null) {
                this.onFocusCallback(this);
            }
        }
    },

    blur: function() {
        if (this.borderVisible == true) {
            this.context.borderDiv.style.border = this.borderWidth + 'px none';
            this.borderVisible = false;

            if (this.onBlurCallback != null) {
                this.onBlurCallback(this);
            }
        }
    },

    //
    // Mouse handlers
    //

    onMouseDown: function(event) {
        if (event.button == Sys.UI.MouseButton.leftButton) {
            event.preventDefault();

            this.dragging = true;
            this.dragPosition = getMousePositionFromRawEvent(event.rawEvent);
            this.dragImagePosition = { x: this.context.regionImage.offsetLeft, y: this.context.regionImage.offsetTop };
            this.context.borderDiv.style.cursor = 'move';

            $addHandler(document, 'mousemove', this.mouseMoveHandler);
            $addHandler(document, 'mouseup', this.mouseUpHandler);
        }
    },

    onMouseMove: function(event) {
        if (this.dragging) {
            event.preventDefault();

            var pos = getMousePositionFromRawEvent(event.rawEvent);

            var left = this.dragImagePosition.x + (pos.x - this.dragPosition.x);
            var top = this.dragImagePosition.y + (pos.y - this.dragPosition.y);

            if (left <= 0 && (left + this.context.regionImage.offsetWidth) > this.width) {
                this.context.regionImage.style.left = left + 'px';
            }
            if (top <= 0 && (top + this.context.regionImage.offsetHeight) > this.height) {
                this.context.regionImage.style.top = top + 'px';
            }
        }
    },

    onMouseUp: function(event) {
        if (this.dragging) {
            $removeHandler(document, 'mousemove', this.mouseMoveHandler);
            $removeHandler(document, 'mouseup', this.mouseUpHandler);
            this.context.borderDiv.style.cursor = 'pointer';
            this.dragging = false;
        }
    },

    //
    // Media Operations
    //

    updateMedia: function(newUrl) {
        this.media.URL = newUrl;
        this.context.regionImage.src = newUrl;
    },

    rotateMedia: function(newUrl) {
        var height = this.media.width;
        var width = this.media.height;
        this.addMedia(this.media.ID, newUrl, width, height, this.media.tint);
    },

    addMediaFromMediaInfo: function(mediaInfo) {
        this.addMedia(mediaInfo.ID, mediaInfo.URL, mediaInfo.width, mediaInfo.height, mediaInfo.tint);
        this.media.Params = new Object();

        for (var name in mediaInfo.Params) {
            this.media.Params[name] = mediaInfo.Params[name];
        }
    },

    addMedia: function(id, url, width, height, tint) {
        var rect = this.calcRect(width, height);

        this.media.ID = id;
        this.media.URL = url;
        this.media.width = width;
        this.media.height = height;
        this.media.tint = tint;

        if (this.context.regionImage != null) {
            this.context.regionImage.style.top = 0 + 'px';
            this.context.regionImage.style.left = 0 + 'px';
            this.context.regionImage.style.width = rect.W + 'px';
            this.context.regionImage.style.height = rect.H + 'px';
            this.context.regionImage.src = url;
        }
    },

    getMediaInfo: function() {
        return this.media;
    },

    //
    // Zoom functionality
    //

    getZoomLevel: function() {
        var rect = this.calcRect(this.media.width, this.media.height);
        var size = this.getDomElementRect(this.context.regionImage);

        var z = 0;
        while (Math.round(rect.W) < size.W && Math.round(rect.H) < size.H) {
            rect.W *= this.zoomFactor;
            rect.H *= this.zoomFactor;
            z++;
        }
        return z;
    },

    setZoomLevel: function(level) {
        var rect = this.calcRect(this.media.width, this.media.height);

        for (var i = 0; i < level; i++) {
            rect.W *= this.zoomFactor;
            rect.H *= this.zoomFactor;
        }

        var size = this.getDomElementRect(this.context.regionImage);

        var deltaW = rect.W - size.W;
        var deltaH = rect.H - size.H;
        var halfDeltaW = deltaW / 2;
        var halfDeltaH = deltaH / 2;
        var newSize = { X: parseInt(size.X - halfDeltaW), Y: parseInt(size.Y - halfDeltaH),
            W: parseInt(size.W + deltaW), H: parseInt(size.H + deltaH)
        };

        this.context.regionImage.style.left = newSize.X + 'px';
        this.context.regionImage.style.top = newSize.Y + 'px';
        this.context.regionImage.style.width = newSize.W + 'px';
        this.context.regionImage.style.height = newSize.H + 'px';

        this.clampImageToAperture();
    },

    //
    // Utility
    //

    clampImageToAperture: function() {
        var rect = this.getDomElementRect(this.context.regionImage);

        if (rect.X > 0) {
            rect.X = 0;
        }

        if (rect.Y > 0) {
            rect.Y = 0;
        }

        if (rect.X + rect.W < this.width) {
            rect.X = this.width - rect.W;
        }

        if (rect.Y + rect.H < this.height) {
            rect.Y = this.height - rect.H;
        }

        this.setDomElementRect(this.context.regionImage, rect);
    },

    calcRect: function(mediaWidth, mediaHeight) {
        var aspect = this.width / this.height;

        var x = mediaWidth / (aspect * mediaHeight);
        var y = (aspect * mediaHeight) / mediaWidth;

        var newLeft = 0;
        var newTop = 0;
        var newWidth = this.width;
        var newHeight = this.height;

        if (x <= 1.0) {
            newWidth = this.width;
            newHeight = Math.round(mediaHeight * (this.width / mediaWidth));
            newLeft = 0;
            newTop = Math.round((this.height - newHeight) / 2);
        }
        else if (y < 1.0) {
            newWidth = Math.round(mediaWidth * (this.height / mediaHeight));
            newHeight = this.height;
            newLeft = Math.round((this.width - newWidth) / 2);
            newTop = 0;
        }

        return { X: newLeft, Y: newTop, W: newWidth, H: newHeight };
    },

    calcZoomRect: function() {
        var rect = this.calcRect(this.media.width, this.media.height);
        var size = this.getDomElementRect(this.context.regionImage);

        while (Math.round(rect.W) < size.W && Math.round(rect.H) < size.H) {
            rect.W *= this.zoomFactor;
            rect.H *= this.zoomFactor;
        }

        return rect;
    },

    calcZoomRectFromCropInfo: function(cropInfo) {
        var rect = this.calcRect(this.media.width, this.media.height);

        var ratioX = this.media.width / rect.W;
        var ratioY = this.media.height / rect.H;

        var top = (cropInfo.top * this.media.height) / ratioY;
        var left = (cropInfo.left * this.media.width) / ratioX;
        var width = ((cropInfo.right * this.media.width) / ratioX) - left;
        var height = ((cropInfo.bottom * this.media.height) / ratioY) - top;

        while (Math.round(width) < this.width && Math.round(height) < this.height) {
            rect.W *= this.zoomFactor;
            rect.H *= this.zoomFactor;
            width *= this.zoomFactor;
            height *= this.zoomFactor;
        }

        return rect;
    },

    getDomElementRect: function(element) {
        var x = this.parseIntFromStyleSize(element.style.left);
        var y = this.parseIntFromStyleSize(element.style.top);
        var w = this.parseIntFromStyleSize(element.style.width);
        var h = this.parseIntFromStyleSize(element.style.height);
        return { X: x, Y: y, W: w, H: h };
    },

    setDomElementRect: function(element, rect) {
        element.style.left = rect.X + 'px';
        element.style.top = rect.Y + 'px';
        element.style.width = rect.W + 'px';
        element.style.height = rect.H + 'px';
    },

    parseIntFromStyleSize: function(styleSize) {
        return parseInt(styleSize.substring(0, styleSize.length - 2));
    },

    getCropInfo: function() {
        if (this.media.ID == null) {
            return null;
        }

        var rect = this.calcZoomRect();

        var scaledLeft = -1 * this.parseIntFromStyleSize(this.context.regionImage.style.left);
        var scaledTop = -1 * this.parseIntFromStyleSize(this.context.regionImage.style.top);

        var ratioX = this.media.width / rect.W;
        var ratioY = this.media.height / rect.H;

        var cropLeft = scaledLeft * ratioX;
        var cropTop = scaledTop * ratioY;
        var cropRight = (this.width + scaledLeft) * ratioX;
        var cropBottom = (this.height + scaledTop) * ratioY;

        cropLeft /= this.media.width;
        cropTop /= this.media.height;
        cropRight /= this.media.width;
        cropBottom /= this.media.height;

        return { left: cropLeft, top: cropTop, right: cropRight, bottom: cropBottom };
    },

    evalResolutionWarning: function() {
        if (this.media.ID == null) {
            return false;
        }

        var cropInfo = this.getCropInfo();

        var width = (cropInfo.right - cropInfo.left) * this.media.width;
        var height = (cropInfo.bottom - cropInfo.top) * this.media.height;

        return (width < this.minRecommendedSize) || (height < this.minRecommendedSize);
    },

    setCropInfo: function(cropInfo) {
        if (this.rendered) {
            var rect = this.calcZoomRectFromCropInfo(cropInfo);

            var ratioX = this.media.width / rect.W;
            var ratioY = this.media.height / rect.H;

            var top = (cropInfo.top * this.media.height) / ratioY;
            var left = (cropInfo.left * this.media.width) / ratioX;
            var width = Math.floor(this.media.width / ratioX);
            var height = Math.floor(this.media.height / ratioY);

            this.setDomElementRect(this.context.regionImage, { X: -left, Y: -top, W: width, H: height });
        }
        else {
            this.cropInfo = cropInfo;
        }
    },

    getSaveInfo: function() {
        var cropInfo = this.cropInfo;

        try {
            cropInfo = this.getCropInfo();
        }
        catch (err) {
        }

        return { ID: this.ID, SessionID: this.getApertureID(), CropInfo: cropInfo, MediaID: this.media.ID };
    }

};

//
// Template Panel - Template Options 
//

function TemplatePanelTemplateOptions()
{
    this.options = new Array;
    this.optionValues = new Array;
}

TemplatePanelTemplateOptions.prototype =
{
    options: null,
    optionValues: null,
    templateOptionChangedCallback: null,
    showSelectOptionsWithOneValue: true,

    addOption: function(id, name, type, values, selectedValue) {
        this.options.push({ ID: id, Name: name, Type: type, Values: values, SelectedValue: selectedValue });
    },

    addOptionValue: function(ids, templateID, price) {
        this.optionValues.push({ IDs: ids, TemplateID: templateID, Price: price });
    },

    setTemplateOptionChangedCallback: function(instance, method) {
        this.templateOptionChangedCallback = Function.createDelegate(instance, method);
    },

    getSaveInfo: function() {
        if (this.options.length == 0) {
            return null;
        }

        var result = new Array;

        for (var i = 0; i < this.options.length; i++) {
            if (!this.options[i].domSelect) {
                continue;
            }

            result.push({ eRetailerProductOptionId: this.options[i].ID,
                eRetailerProductOptionValue: this.getOptionValueByIndex(i),
                RetailerProductOptionValueText: ''
            });
        }

        if (result.length > 0) {
            return result;
        }
        else {
            return null;
        }
    },

    getOptionValueByIndex: function(index) {
        return this.options[index].domSelect.options[this.options[index].domSelect.selectedIndex].value;
    },

    getOptionValues: function() {
        var values = new Array;

        for (var i = 0; i < this.options.length; i++) {
            if (this.options[i].Type != 3) {
                continue;
            }

            if (this.options[i].domSelect != null) {
                values.push(this.getOptionValueByIndex(i));
            }
            else {

                //we should get the current value, not just 
                //the first one if it is available.  bug #8510
                if (this.options[i].SelectedValue)
                    values.push(this.options[i].SelectedValue);
                else
                    values.push(this.options[i].Values[0].id);
            }
        }

        return values;
    },

    getOptionValue: function() {
        var values = this.getOptionValues();

        for (var i = 0; i < this.optionValues.length; i++) {
            var optionValue = this.optionValues[i];
            var optionFound = false;

            for (var j = 0; j < values.length; j++) {
                optionFound = false;

                for (var k = 0; k < optionValue.IDs.length; k++) {
                    if (optionValue.IDs[k] == values[j]) {
                        optionFound = true;
                        break;
                    }
                }

                if (optionFound == false) {
                    break;
                }
            }

            if (optionFound == true) {
                return this.optionValues[i];
            }
        }

        return null;
    },

    getPrice: function() {
        var value = this.getOptionValue();

        if (value != null) {
            return value.Price;
        }
        else {
            return null;
        }
    },

    getTemplateID: function() {
        var value = this.getOptionValue();

        if (value != null) {
            return value.TemplateID;
        }
        else {
            return null;
        }
    },

    onTemplateOptionChanged: function() {
        if (this.templateOptionChangedCallback != null) {
            this.templateOptionChangedCallback(this.getTemplateID(), this.getOptionValues());
        }
    },

    render: function(parentID) {
        if (parentID == null || parentID.length == 0) {
            return;
        }

        var parent = document.getElementById(parentID);

        if (parent == null && this.options.length == 0) {
            return;
        }

        for (var i = 0; i < this.options.length; i++) {
            var option = this.options[i];

            if (option.Type != 3) {
                continue;
            }

            var select = option.domSelect = document.createElement('select');
            select.setAttribute("id", "templateOptionsSelect" + i.toString());

            select.owner = this;
            select.onchange = function(event) { this.owner.onTemplateOptionChanged(); };

            var selectedIndex = 0;

            for (var j = 0; j < option.Values.length - 1; j++) {
                var select_option = document.createElement('option');
                select_option.innerHTML = option.Values[j].name;
                select_option.value = option.Values[j].id;
                select.appendChild(select_option);

                if (option.Values[j].id == option.SelectedValue) {
                    selectedIndex = j;
                }
            }

            select.selectedIndex = selectedIndex;

            var container = document.createElement('div');
            container.className = 'left';

            if (i != this.options.length - 1) {
                //                container.style.marginRight = '16px';
            }

            if (this.showSelectOptionsWithOneValue === false && option.Values.length <= 2)  // last option is undefined/null
            {
                container.style.display = 'none';
            }

            var divOptionName = document.createElement('div');
            divOptionName.setAttribute("id", "optionName");
            divOptionName.appendChild(document.createTextNode(option.Name + ': '));

            var divOptionValue = document.createElement('div');
            divOptionValue.setAttribute("id", "optionValue");
            divOptionValue.appendChild(select);

            container.appendChild(divOptionName);
            container.appendChild(divOptionValue);

            parent.appendChild(container);
        }
    }

};

Type.registerNamespace('PhotoSite');

var giftService = null;
var productView = null;

function initServiceView() {
    if (!giftService) {
        giftService = new IGiftService();
    }

    if (!productView) {
        productView = new PhotoSite.photoGiftGroup();
    }

    if (!categoryService)
        categoryService = new ICategoryService();
}

var photoGiftGroups = new Array();

PhotoSite.photoGift = function(encId, encCategoryId, encProductPlacementId, name, thumbUrl, price, type, description, options, layoutKey, reWrittenUrl) {
    this._encId = encId;
    this._encCategoryId = encCategoryId;
    this._encProductPlacementId = encProductPlacementId;
    this._name = name;
    this._description = description;
    this._thumbUrl = fileExists(thumbUrl.replace('../', '/')) ? thumbUrl.replace('../', '/') : "/images/no_image" + SR.LanguageSuffix + ".gif";
    this._price = price;
    this._type = type;
    this._options = options;
    this._layoutKey = layoutKey;
    this._reWrittenUrl = reWrittenUrl;
}

PhotoSite.photoGiftSubGroup = function(encId, encCategoryId, encProductPlacementId, name, description, thumbUrl, price, layoutKey) {
    this._encId = encId;
    this._encCategoryId = encCategoryId;
    this._encProductPlacementId = encProductPlacementId;
    this._name = name;
    this._description = description;
    this._thumbUrl = fileExists(thumbUrl.replace('../', '/')) ? thumbUrl.replace('../', '/') : "/images/no_image" + SR.LanguageSuffix + ".gif";
    this._price = price;
    this._type = "Category";
    this._layoutKey = layoutKey;
}
PhotoSite.photoGiftSubGroup.prototype = {
    render: function(parent) {

        var container = this._domElement = document.createElement('div');

        container.id = this._encId + '_product_thumb';
        container.className = 'gift_content';

        var sb = new Sys.StringBuilder();

        if (new RegExp('collage').test(this._name.toLowerCase()))
            this._type = "Collages";
        else if (new RegExp('newspapers').test(this._name.toLowerCase()))
            this._type = "Newspapers";
        if (this.productType == "EnhancementPrints")
            this._type = "EnhancementPrints";

        var name = this._name == null || this._name.toString().trim() == '' ? "&nbsp;" : sanitizeText(this._name);

        sb.append("<div class='product_listing_thumb' style='width:120px'><p>");
        sb.append("<a href=\"javascript:selectPhotoGift('");
        sb.append(this._type);
        sb.append("','");
        sb.append(this._encId);
        sb.append("','");
        sb.append(this._encCategoryId);
        sb.append("','");
        sb.append(this._encProductPlacementId);
        sb.append("','");
        sb.append(this._layoutKey);
        
        sb.append("')\"><img src='");
        sb.append(fileExists(this._thumbUrl) ? this._thumbUrl : "../images/no_image" + SR.LanguageSuffix + ".gif");
        sb.append("' border='0' alt='");
        sb.append(name);
        sb.append("' title='Click here for ");
        sb.append(name);
        sb.append("'/></a></p></div>");
        sb.append("<div class='product_listing_desc'><h3 class='product_label'>");
        sb.append(name);
        sb.append("</h3><h1 class='price_red'><p>" + canUseFrom(this._price) + "&nbsp;");
        sb.append(this._price);
        sb.append("</p></h1><p>");

        var description = this._description == null || this._description.toString().trim() == '' ? "&nbsp;" : sanitizeText(this._description);

        sb.append(description);
        sb.append("</div></div><div class='product_listing_btn' style='padding-top: 90px'><a href=\"javascript:selectPhotoGift('");
        sb.append(this._type);
        sb.append("','");
        sb.append(this._encId);
        sb.append("','");
        sb.append(this._encCategoryId);
        sb.append("','");
        sb.append(this._encProductPlacementId);
        sb.append("','");
        sb.append(this._layoutKey);
        sb.append("')\"><img src='/images/btns/btn_start_here" + SR.LanguageSuffix + ".gif' border='0' /></a></div>");

        container.innerHTML = sb.toString();
        parent.appendChild(container);
    }
}


function canUseFrom(price) {
    var leastPrice = 0;
    try {
        leastPrice = parseFloat(price.replace("$", "").replace("£", ""));
    }
    catch (e) { }

    return leastPrice > 0 ? SR.From : "";
}

PhotoSite.photoGift.prototype =
{
    _type: null,
    _domElement: null,

    render: function(parent) {

        var container = this._domElement = document.createElement('div');

        container.id = this._encId + '_product_thumb';
        container.className = 'gift_content';

        var htmlMarkup = new Sys.StringBuilder();

        var name = this._name == null || this._name.toString().trim() == '' ? "&nbsp;" : sanitizeText(this._name);

        htmlMarkup.append("<div class='product_listing_thumb' style='width:120px'><p>");
        htmlMarkup.append("<a href=\"javascript:selectPhotoGift('");
        htmlMarkup.append(this._type);
        htmlMarkup.append("','");
        htmlMarkup.append(this._encId);
        htmlMarkup.append("','");
        htmlMarkup.append(this._encCategoryId);
        htmlMarkup.append("','");
        htmlMarkup.append(this._encProductPlacementId);
        htmlMarkup.append("','");
        htmlMarkup.append(this._layoutKey);
        htmlMarkup.append("','");
        htmlMarkup.append(this._reWrittenUrl);         
        htmlMarkup.append("')\"><img src='");
        htmlMarkup.append(this._thumbUrl);
        htmlMarkup.append("' border='0' alt='");
        htmlMarkup.append(name);
        htmlMarkup.append("' title='Click here for ");
        htmlMarkup.append(name);
        htmlMarkup.append("'/></a></p></div>");
        htmlMarkup.append("<div class='product_listing_desc'><h3 class='product_label'>");
        htmlMarkup.append(name);
        htmlMarkup.append("</h3><h1 class='price_red'><p>");
        htmlMarkup.append(canUseFrom(this._price) + "&nbsp;" + this._price);
        htmlMarkup.append("</p></h1><p>");

        //htmlMarkup.append("<div class='gift_features_container'>");

        //        if (this._options.length > 0) {
        //            htmlMarkup.append("<div class='gift_features_separator'>");
        //            htmlMarkup.append(this.getOptionsMarkup(this._options));
        //            htmlMarkup.append("</div>");
        //        }
        //        else {
        //            //Add empty space
        //            htmlMarkup.append("<div class='empty_gift_features_container'>&nbsp;</div>");
        //        }


        var description = this._description == null || this._description.toString().trim() == '' ? "&nbsp;" : sanitizeText(this._description);

        //htmlMarkup.append("<div class='gift_features_separator'>");
        htmlMarkup.append(description);
        //htmlMarkup.append("</div>");

        //htmlMarkup.append("<div class='start_here'>")
        htmlMarkup.append("</div><div class='product_listing_btn' style='padding-top: 90px'><a href=\"javascript:selectPhotoGift('");
        htmlMarkup.append(this._type);
        htmlMarkup.append("','");
        htmlMarkup.append(this._encId);
        htmlMarkup.append("','");
        htmlMarkup.append(this._encCategoryId);
        htmlMarkup.append("','");
        htmlMarkup.append(this._encProductPlacementId);
        htmlMarkup.append("','");
        htmlMarkup.append(this._layoutKey);
        htmlMarkup.append("','");
        htmlMarkup.append(this._reWrittenUrl);        

        htmlMarkup.append("')\"><img src='/images/btns/btn_start_here" + SR.LanguageSuffix + ".gif' border='0'/></a></div>");

        container.innerHTML = htmlMarkup.toString();
        parent.appendChild(container);
    },

    getOptionsMarkup: function(options) {

        var optionMarkup = new Sys.StringBuilder();

        for (var i = 0; i < options.length; i++) {

            var option = options[i];

            if (option.OptionValues.length > 0) {

                optionMarkup.append("<div class='preview_features' style='width: 120px;'><p><strong>");
                optionMarkup.append(option.Name);
                optionMarkup.append(":</strong></p>");
                optionMarkup.append("<ul>");

                for (var j = 0; j < option.OptionValues.length; j++) {

                    var optionValue = option.OptionValues[j];

                    optionMarkup.append("<li>");
                    optionMarkup.append(optionValue.Text);

                }

                optionMarkup.append("</ul>");
                optionMarkup.append("</div>");
            }

        }

        return optionMarkup.toString();

    }

}

PhotoSite.photoGiftGroup = function(groupId) {
    this._groupId = groupId;
}

PhotoSite.photoGiftGroup.prototype =
{
    _photoGifts: new Array(),

    addPhotoGift: function(photoGift) {
        this.photoGifts.push(photoGift);


    },

    getPhotoGifts: function() {
        return this._photoGifts;
    }

}

function selectPhotoGift(type, rpId, id, pplId, layoutKey, reWrittenUrl) {

    if (isEmptyOrEncryptedZero(layoutKey)) {
        switch (type.toLowerCase()) {
            case 'category':
                checkSessionTimeout();
                if (rpId != '' & rpId != null & photoGiftGroups.length > 0 & !isEmptyOrEncryptedZero(id)) {
                    if (renderSubcategoryContents(id, rpId))
                        break;
                }
                else if (!isEmptyOrEncryptedZero(rpId) & rpId != null & isEmptyOrEncryptedZero(id)) {
                    selectPhotoGift('', rpId, id, pplId, layoutKey)
                    break;
                }
                UpdateNavigation2(pplId, id);
                selectdeselect(selSubMenuDivPrefix + id, selSubMenuPrefix + id, pplId);
                break;
            case 'calendars':
                location.href = RootUrl + "album/calendar_options.aspx?q=" + rpId;
                break;
            case 'photocalendars':
            case 'photocalendar':
                location.href = RootUrl + "album/calendar_custom_options.aspx?q=" + rpId;
                break;
            case 'photobooks':
            case 'photobook':
                location.href = RootUrl + "album/photobook_landing.aspx";
                break;
            case 'collages':
                location.href = RootUrl + "album/collagepage.aspx";
                break;
            case 'cd':
            case 'photocd':
                location.href = photo_albumUrl + "?path=1ePyT1lSuBl5zKzO_BSU5WXU7pvw3lfgy";
                break;
            case 'newspapers':
                location.href = RootUrl + "album/personalised_newspaper_landing.aspx";
                break;
            default:
                if (isEmptyOrEncryptedZero(reWrittenUrl) || urlRewriteEnabled == "False")
                    location.href = RootUrl + "album/gifts_select_media.aspx?q=" + rpId;
                else if (!isEmptyOrEncryptedZero(pplId) && !isEmptyOrEncryptedZero(id) && isEmptyOrEncryptedZero(reWrittenUrl))
                    UpdateNavigation2(pplId, id);
                else
                    location.href = RootUrl + reWrittenUrl;
                break;
        }
    }
    else {
        try { updateNavigatorforSpecialisedGifts(rpId, id, pplId); } catch (e) { }

        if (isEmptyOrEncryptedZero(reWrittenUrl))
            location.href = RootUrl + "album/specialised_gifts_landing.aspx?q=" + id + "&lkey=" + layoutKey;
        else
            location.href = RootUrl + reWrittenUrl;
    }
}


function renderSubcategoryContents(catId, subCatId) {
    var photogiftGroup = getPhotoGiftGroup(catId);

    if (photogiftGroup != null) {
        var subGroup = null;
        subGroup = getPhotogiftSubcategoryBySubcategoryId(photogiftGroup.PhotoGiftSubGroupModels, subCatId);
        if (subGroup) {
            RenderProductCategoryContentResults(subGroup);
            return true
        }
    }
    return false;
}


function RenderProductCategoryContentResults(result) {

    var photoGiftGroup = result;

    var resultContainer = $get('gifts_landing_main_content');

    if (photoGiftGroup != null) {

        resultContainer.innerHTML = "";
        $get('gifts_categories_header').innerHTML = photoGiftGroup.Name;

        var categoryContents = new Array();

        //sort array contents
        var sortedPhotoGiftSubGroupModels = photoGiftGroup.PhotoGiftSubGroupModels.sort(sortModels);
        var sortedPhotoGiftModels = photoGiftGroup.GiftModels.sort(sortModels);

        //merge sorted contents
        categoryContents = categoryContents.concat(sortedPhotoGiftSubGroupModels, sortedPhotoGiftModels);

        if (categoryContents.length > 0) {
            for (var i = 0; i < categoryContents.length; i++) {

                var model = categoryContents[i];

                if (model != null) {
                    if (model.ModelType == "gift") {
                        var photoGift = new PhotoSite.photoGift(model.EncId, photoGiftGroup.Id, photoGiftGroup.ProductPlacementId, model.Name, model.ThumbUrl, model.FormatedLeastPrice, model.ProductType, model.Description, model.PhotoGiftOptions, model.LayoutKey, model.RetailerProductUrl);
                        photoGift.render(resultContainer);
                    }
                    else if (model.ModelType == "giftsubgroup") {
                        var photoGiftSubGroup = new PhotoSite.photoGiftSubGroup(model.Id, photoGiftGroup.Id, photoGiftGroup.ProductPlacementId, model.Name, model.Description, model.ThumbUrl, model.FormatedLeastPrice, model.LayoutKey);

                        photoGiftSubGroup.render(resultContainer);
                    }
                }
            }
        }
        if (!isGroupAlreadyRendered(photoGiftGroup.Id))
            photoGiftGroups.push(photoGiftGroup);
    }

    hideLoadingPopup();
}

function getPhotogiftSubcategoryBySubcategoryId(photoGiftGroupSubCategories, subCategoryIdtoReturn) {
    for (var i = 0; i < photoGiftGroupSubCategories.length; i++) {
        var subGroup = photoGiftGroupSubCategories[i];
        if (subGroup.Id == subCategoryIdtoReturn)
            return subGroup;
    }
}

function isGroupAlreadyRendered(groupId) {

    for (var i = 0; i < photoGiftGroups.length; i++) {
        var group = photoGiftGroups[i];
        if (group.Id == groupId)
            return true;
    }
    return false;
}

function getPhotoGiftGroup(groupId) {
    for (var i = 0; i < photoGiftGroups.length; i++) {
        var group = photoGiftGroups[i];
        if (group.Id == groupId)
            return group;
    }
    return null;
}

function GetProductCategoryContent() {
    showLoadingPopup(res_loadingText);
    initServiceView();
    giftService.GetCategoryPhotoGiftModelsInstance(OnGotProductCategoryContentResult, gotError);
}

function OnGotProductCategoryContentResult(result) {
    if (result) {
        RenderProductCategoryContentResults(Sys.Serialization.JavaScriptSerializer.deserialize(result));
    }
}

var selSubMenuPrefix = 'a_side_nav_category';
var selSubMenuDivPrefix = 'div_side_nav_sub_category';

function selectChosenSubMenuFromMaimMenu(ppId, catId) {

    if (isEmptyOrEncryptedZero(catId)) {
        renderAllCategoriesinProdPlacement(); return;
    }

    var selSubMenu = $get(selSubMenuPrefix + catId);
    var selSubMenuDiv = $get(selSubMenuDivPrefix + catId);

    if (selSubMenu != null && selSubMenuDiv != null) {
        selectdeselect(selSubMenuDiv.id, selSubMenu.id, ppId);
        renderCategorySample(selectedCategory, 'gifts_landing_main_content');
    }
    else
        renderAllCategoriesinProdPlacement();
}

var res_loadingText = SR.Loading;
var selectedCategory = '';

function selectdeselect(selectedCatDivId, selectedCatHeaderId, pplId) {

    var currentCategory = selectedCatHeaderId.substring(19);

    if (selectedCategory == currentCategory)
        return;

    if (selectedCategory != '') {
        var selSubMenuLinkPrefix = $get(selSubMenuPrefix + selectedCategory);
        if (selSubMenuLinkPrefix)
            selSubMenuLinkPrefix.className = "side_nav_cat_unselected";

        var selSubCatMenuDivPrefix = $get(selSubMenuDivPrefix + selectedCategory);
        if (selSubCatMenuDivPrefix)
            selSubCatMenuDivPrefix.className = "side_nav_sub_unselected";
    }
    var selCurrentSubMenuPrefix = $get(selSubMenuPrefix + currentCategory);
    if (selCurrentSubMenuPrefix)
        selCurrentSubMenuPrefix.className = "side_nav_cat_selected"

    var selCurrentSubMenuDivPrefix = $get(selSubMenuDivPrefix + currentCategory);
    if (selCurrentSubMenuDivPrefix)
        selCurrentSubMenuDivPrefix.className = "side_nav_sub_selected";

    selectedCategory = currentCategory;
    currentGroupId = '';
}

function renderAllCategoriesinProdPlacement() {

    var parent = $get('gifts_landing_main_content');

    showLoadingPopup(res_loadingText);

    for (var i = 0; i < categories.length; i++) {
        var cat = categories[i];

        var div = document.createElement("div");
        div.className = "product_listing";
        div.innerHTML = getCategorySampleHTML(cat);

        parent.appendChild(div);
    }

    if (categories.length > 0) {
        var placementId = categories[0].pplId;
        var placementName = "Gift Ideas";
        switch (placementId) {
            case '1wL31xSALXQG2BG4DLfsDPEzisRkMPCqF':
                placementName = "Canvas &amp; Posters";
                break;
            case '1Uz5De5GHPRTdeCaLBCHJggZ1bY0Hh0sb':
                placementName = "Restoration &amp; Caricatures";
                break;
            case '1tJHqTB,glCJdT3MYpet5WpqwOARm9GXE':
                placementName = "Gift Ideas"
                break;
        }
        $get('gifts_categories_header').innerHTML = placementName;
    }

    hideLoadingPopup();
}

function getCategorySampleHTML(cat) {

    if (cat == null)
        return '';

    var sb = new Sys.StringBuilder();

    if (cat.hasCategory.toLowerCase() == "true")
        cat.type = "Category";

    if (new RegExp('collage').test(cat.name.toLowerCase()))
        cat.type = "Collages";

    if (new RegExp('newspapers').test(cat.name.toLowerCase()))
        cat.type = "Newspapers";

    if (cat.productType == "EnhancementPrints")
        cat.type = "EnhancementPrints";


    var name = cat.name == null || cat.name.toString().trim() == '' ? "&nbsp;" : sanitizeText(cat.name);

    sb.append("<div class='product_listing_thumb' style='width:120px'><p>");
    sb.append("<a href=\"javascript:selectPhotoGift('");
    sb.append(cat.type);
    sb.append("','");
    sb.append(cat.rpId);
    sb.append("','");
    sb.append(cat.id);
    sb.append("','");
    sb.append(cat.pplId);
    sb.append("','");
    sb.append(cat.layoutKey);
    sb.append("','");
    sb.append(cat.reWrittenUrl);
    sb.append("')\"><img src='");
    sb.append(fileExists(cat.sampleImageUrl) ? cat.sampleImageUrl : "../images/no_image" + SR.LanguageSuffix + ".gif");
    sb.append("' border='0' alt='");
    sb.append(name);
    sb.append("' title='Click here for ");
    sb.append(name);
    sb.append("'/></a></p></div>");
    sb.append("<div class='product_listing_desc'><h3 class='product_label'>");
    sb.append(name);
    sb.append("</h3><h1 class='price_red'><p>" + canUseFrom(cat.minPrice) + "&nbsp;");
    sb.append(cat.minPrice);
    sb.append("</p></h1><p>");
    sb.append(cat.description);
    sb.append("</p></div><div class='product_listing_btn' style='padding-top: 90px'><a href=\"javascript:selectPhotoGift('");
    sb.append(cat.type);
    sb.append("','");
    sb.append(cat.rpId);
    sb.append("','");
    sb.append(cat.id);
    sb.append("','");
    sb.append(cat.pplId);
    sb.append("','");
    sb.append(cat.layoutKey);
    sb.append("','");
    sb.append(cat.reWrittenUrl);

    sb.append("')\"><img src='/images/btns/btn_start_here" + SR.LanguageSuffix + ".gif' border='0' /></a></div></div>");

    return sb.toString();
}

function renderCategorySample(id, parentDivId) {

    var parentDiv = $get(parentDivId);
    var cat = getCategoryById(id);

    if (cat) {
        $get('divPromo').style.display = "none";
        $get('gifts_categories_header').innerHTML = cat.name;
        parentDiv.innerHTML = getCategorySampleHTML(cat);
    }
}

function updateSelectedCategoryNavigator(catId, pplId) {

    if (currentGroupId == catId)
        return;

    if (!isEmptyOrEncryptedZero(catId) & currentGroupId != catId)
        currentGroupId = catId;

    if (!categoryService)
        categoryService = new ICategoryService();

    var state = new Object();
    state.EProductPlacementID = pplId;
    state.ECategoryID = catId;

    categoryService.UpdateNavigator2(state, true, function() { renderCategorySample(catId, 'gifts_landing_main_content'); }, gotError);
}

function getCategoryById(id) {

    for (var i = 0; i < categories.length; i++) {

        var cat = categories[i];
        if (cat.id == id)
            return cat;
    }

    return null;
}

var currentGroupId = '';

function UpdateNavigation2(productPlacementContentId, productCategoryId, retailerProductId) {

    var groupId = productCategoryId;

    if (isEmptyOrEncryptedZero(groupId) & !isEmptyOrEncryptedZero(retailerProductId))
        groupId = retailerProductId;

    currentGroupId = groupId;

    if (categoryService == null)
        categoryService = new ICategoryService();

    if (!isGroupAlreadyRendered(groupId)) {
        var navigationState = new Object;

        navigationState.EProductPlacementID = productPlacementContentId;
        navigationState.ERetailerProductID = retailerProductId;
        navigationState.ECategoryID = productCategoryId;
        categoryService.UpdateNavigator2(navigationState, false, UpdateGiftNavigationSessionCompleted2, gotError);
    }
    else {
        //Get contents from local cache
        var contents = getPhotoGiftGroup(groupId);

        if (typeof contents != 'undefined' && contents != null)
            showLoadingPopup(res_loadingText);

        RenderProductCategoryContentResults(contents);
    }
}

function updateNavigatorforSpecialisedGifts(rpId, catid, pplId) {
    var state = new Object();

    state.EProductPlacementID = pplId;
    state.ECategoryID = catid;
    state.ERetailerProductID = rpId;

    if (categoryService == null)
        categoryService = new ICategoryService();

    categoryService.UpdateNavigator(state, false, function(res) {
        ////    alert(res); 
    }, gotError)
}

function isEmptyOrEncryptedZero(value) {
    return typeof value == "undefined" || value == "" || value == "1dEvH,sBwBIX9pvpibXIiNSHIpK2SU,Dj" || value == '1g,ZRY1n4Xt1UeK2KJo3UGNlOZyB05UEK';
}

function UpdateGiftNavigationSessionCompleted2(result) {
    var objResult = Sys.Serialization.JavaScriptSerializer.deserialize(result);
    var url = document.location.href;

    var productTypeId = parseInt(objResult.ProductTypeId);

    if (url.indexOf('https:') > -1) {
        document.location = '<%=AppGlobal.GetAbsoluteBaseUrl() %>/' + objResult.Url;
    }
    else if (objResult.ProductTypeId == '3' || objResult.ProductTypeId == '5' || objResult.ProductTypeId == '12') {
        GetProductCategoryContent();
    }
    else {
        document.location = RootUrl + objResult.Url;
    }
}

function sortModels(model1, model2) {
    if (model1 != null & model2 != null)
        return model1.Name >= model2.Name ? 1 : 0;
    else if (model1 != null & model2 == null)
        return 0;
    else if (model1 == null & model2 != null)
        return 1;
    else //default
        return 1;
}

function sanitizeText(texttoSanitize) {
    if (texttoSanitize == null)
        return "";
    var sanitizedText = texttoSanitize;
    sanitizedText = texttoSanitize.toString().replace("'", "&#39;").replace('"', '&quot;');

    return sanitizedText;
}

function initializeGiftSelectMediaOrderOptions() {

    var selectedPackageOption = $get("<%=SelectedPackageOption.ClientID %>");

    if (selectedPackageOption != null) {
        if (selectedPackageOption.value != "") {
            var defaultRpovId = selectedPackageOption.value;
            $get("opt_" + defaultRpovId).checked = 'checked';
            rpovTotal.innerHTML = $get("price_" + defaultRpovId).innerHTML;
        }
    }

    var basePrice = $get("basePrice");
    if (basePrice != null) {
        if (basePrice.innerHTML == "")
            rpovTotal.style.display = "";
    }
}



PhotoSite.photoGiftGroup.registerClass('PhotoSite.photoGiftGroup');
PhotoSite.photoGift.registerClass('PhotoSite.photoGift');

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();