/****************************************************************************
 * Copyright (c) 1998-2007 Luna Imaging, Inc.  All Rights Reserved.
 *
 * This software is confidential and proprietary information of
 * Luna Imaging, Inc.  ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Luna Imaging, Inc.
 *
 * The software may not be copied, reproduced, translated or reduced to
 * any electronic medium or machine-readable form without
 * the prior written consent of Luna Imaging.
 *
 * You are not allowed to distribute the binary and source code
 * (if released) to third parties, without the prior written consent from
 * Luna Imaging.
 *
 * You are not allowed to reverse engineer, disassemble or decompile
 * code, or make any modifications of the binary or source code, remove
 * or alter any trademark, logo, copyright or other proprietary notices,
 * legends, symbols, or labels in the Software.
 *
 * You are not allowed to sub-license the Software or any derivative
 * work based on or derived from the Software.
 *
 * LUNA IMAGING MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
 * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
 * A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, LUNA IMAGING SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
 * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 *
 *  cruiz10020@yahoo.com
 *
 *  MediaGroupPanelManager.js
 *
 *  Description:
 *    Manager for Image panels
 *
 *  Structure:
 *
 *
 *  Requires:
 *    prototype.js - http://www.prototypejs.org/
 *
 *  Development History:
 *    5-14-2007       - created
 *
 *******************************************************************************/

function MediaGroupPanelManager( container, header, helpUrl, timeoutMilli, messageToUser, requestUpdateSlideImage, requestSaveSlide, requestDeleteSlideImage, postResizeFunction, postDestroyFunction, addImagePanelInfo, addThumbnailPanner )
{
  this.mContainer = $(container);
  this.mHeaderContainer = (header) ? $( header ) : null;
  this.mHeader =  (this.mHeaderContainer) ? this.mHeaderContainer.getElementsBySelector( 'h1' )[0] : null;
  this.mImagePanels = $(new Array());
  this.mLoadingContainer = null;
  this.mFunctionMessageToUser = messageToUser;
  this.mFunctionRequestUpdateSlideImage = requestUpdateSlideImage;
  this.mFunctionRequestSaveSlide = requestSaveSlide;
  this.mFunctionRequestDeleteSlideImage = requestDeleteSlideImage;
  this.mPostResizeFunction = postResizeFunction;
  this.mPostDestoryFunction = postDestroyFunction;
  this.mCurrentImagePanel = null;
  this.mHelpUrl = helpUrl;
  this.mSlidesPanel = null;
  this.mImagesPanel = null
  this.mCurrentWorkingPresentation = null;
  this.mCurrentWorkingSlide = null;
  this.mMediaPanelInfo = null;
  this.mThumbnailPanner = null;
  this.mTimeout = timeoutMilli;
  this.mCurrentRatio = null;
  this.mImageNotAvailableUrl = null;
  this.mFlashPlayerUrl = null;
  this.mTemplateUrlPrefix = null;

  this.mPostSaveOperations = $([]);

  // Flags
  this.mUpdatingSlideInProgress = null;
  this.mUpdatingSlideTimeStamp = null;
  this.mResettingWorkspace = null;
  this.mLoading = null;
  this.mLoadingStartTime = null;
  this.mAnimate = true;
  this.mWindowingControlsOnly = false;

  // constants
  this.RESTORE_CONFIRMATION = ' This will clear the current workspace. Do you want to continue? ';
  this.LOADING_CONTAINER = 'loadingContainer';
  this.LOADING_MESSAGE = '';
  this.NO_NAME = '[No Description]';

  this.MIN_LOADING_TIME = 1500;  // 1.5 seconds in milliseconds
  this.MAX_HEADER_MESSAGE_LENGTH = 68;
  this.DEFAULT_WORKSPACE_SIZE = $([ 16, 9 ]);
  this.SCALING_SCALE_FACTOR_THRESHOLD = [0.5, 1.5];
  this.SAVE_ROUNDING_SIGNIFICANTE_DIGITS = 4;

  // create and render control
  //this.mControl = new ImagePanelControls( Static_MediaGroupPanelManager_CurrentActionHasChanged, Static_MediaGroupPanelManager_CacnelCurrentAction );
  //this.mControl.render( this.mHeaderContainer );
  //this.mControl.mManager = this;

  // function mappings
  this.init = MediaGroupPanelManager_Init;

  this.bringToFront = MediaGroupPanelManager_BringToFront;
  this.indexOfPanel = MediaGroupPanelManager_IndexOfPanel;
  this.centerOnContainer = MediaGroupPanelManager_CenterOnContainer;
  this.closeAllImagePanels = MediaGroupPanelManager_CloseAllImagePanels;
  this.closeCurrentSlide = MediaGroupPanelManager_CloseCurrentSlide;
  this.closeCurrentPresentation = MediaGroupPanelManager_CloseCurrentPresentation;

  this.getImagePanelByMediaId = MediaGroupPanelManager_GetImagePanelByMediaId;
  this.getImagePanelByIdentity = MediaGroupPanelManager_GetImagePanelByIdentity;
  this.getStartingPosition = MediaGroupPanelManager_GetStartingPosition;
  this.getCurrentTotalNumberOfSlides =MediaGroupPanelManager_GetCurrentTotalNumberOfSlides;
  this.getCurrentSlideIndex = MediaGroupPanelManager_GetCurrentSlideIndex;
  this.getCurrentImagePanel = MediaGroupPanelManager_GetCurrentImagePanel;
  this.setCurrentImagePanel = MediaGroupPanelManager_SetCurrentImagePanel;
  this.setSlidesPanel = MediaGroupPanelManager_SetSlidesPanel;
  this.setImagesPanel = MediaGroupPanelManager_SetImagesPanel;
  this.setAnimate = MediaGroupPanelManager_SetAnimate;

  this.saveCurrentSlide = MediaGroupPanelManager_SaveCurrentSlide;
  this.updateCurrentSlide = MediaGroupPanelManager_UpdateCurrentSlide;
  this.markSlideAsSaved = MediaGroupPanelManager_MarkSlideAsSaved;

  this.createImagePanel = MediaGroupPanelManager_CreateImagePanel;
  this.restoreWorkspace = MediaGroupPanelManager_RestoreWorkspace;
  this.restoreWorkspaceByIndex = MediaGroupPanelManager_RestoreWorkspaceByIndex;
  this.resetWorkspace = MediaGroupPanelManager_ResetWorkspace;
  this.resizeWorkspace = MediaGroupPanelManager_ResizeWorkspace;
  this.rescaleWorkspace = MediaGroupPanelManager_RescaleWorkspace;
  this.deriveImagePanelState = MediaGroupPanelManager_DeriveImagePanelState;
  this.addImagePanel = MediaGroupPanelManager_AddImagePanel;
  this.removeImagePanel = MediaGroupPanelManager_RemoveImagePanel;
  this.constructSlideImagesToSave = MediaGroupPanelManager_ConstructSlideImagesToSave;
  this.getCurrentSlide = MediaGroupPanelManager_GetCurrentSlide;
  this.getCurrentPresentation = MediaGroupPanelManager_GetCurrentPresentation;
  this.setCurrentPresentation = MediaGroupPanelManager_SetCurrentPresentation;
  this.getCurrentWorkspaceRatio = MediaGroupPanelManager_GetCurrentWorkspaceRatio;
  this.setImageNotAvailableUrl = MediaGroupPanelManager_ImageNotAvailableUrl;
  this.setFlashPlayerUrl = MediaGroupPanelManager_SetFlashPlayerUrl;
  this.setTemplateUrlPrefix = MediaGroupPanelManager_SetTemplateUrlPrefix;

  this.updateHeader = MediaGroupPanelManager_UpdateHeader;
  this.imagePanelChanged = MediaGroupPanelManager_ImagePanelChanged;

  this.addPostSaveOperation = MediaGroupPanelManager_AddPostSaveOperation;
  this.notifySildeSaved = MediaGroupPanelManager_NotifySildeSaved;

  this.startLoadingState = MediaGroupPanelManager_StartLoadingState;
  this.endLoadingState = MediaGroupPanelManager_EndLoadingState;

  this.showHelpPage = MediaGroupPanelManager_ShowHelpPage;
  this.showMessageToUser = MediaGroupPanelManager_ShowMessageToUser;

  // initialize our selves
  this.init( addImagePanelInfo, addThumbnailPanner );
}

function MediaGroupPanelManager_Init( addImagePanelInfo, addThumbnailPanner )
{
  // create loading container
  this.mLoadingContainer = $( document.createElement( 'div' ) );

  // add it to the body
  this.mContainer.appendChild( this.mLoadingContainer );

  // set class name
  this.mLoadingContainer.addClassName( this.LOADING_CONTAINER );

  // hide it right away
  this.mLoadingContainer.hide();

  // stylings
  var dimensions = jshGetWindowSize();
  this.mLoadingContainer.style.position = 'absolute';
  this.mLoadingContainer.style.top = 0 + 'px';
  this.mLoadingContainer.style.left = 0 + 'px';
  this.mLoadingContainer.style.width = ( dimensions[0] )  + 'px';
  this.mLoadingContainer.style.height = ( dimensions[1] ) + 'px';
  this.mLoadingContainer.style.overflow = 'hidden';
  this.mLoadingContainer.style.zIndex = '5000';

  jshSetOpacity( this.mLoadingContainer, .75 );

  // give it a message
  this.mLoadingContainer.update( this.LOADING_MESSAGE );

  // image info
  if( addImagePanelInfo == true )
  {
    this.mMediaPanelInfo = new ImagePanelInformation();
    this.mMediaPanelInfo.render( this.mContainer );
  }

  if( addThumbnailPanner == true )
  {
    this.mThumbnailPanner = new ThumbnailPanner();
    this.mThumbnailPanner.render( this.mContainer );
  }
}

/**
 * Returns the index of the given panel within the array of images currently
 * being managed.
 */
function MediaGroupPanelManager_IndexOfPanel( imagePanel )
{
  return this.mImagePanels.indexOf( imagePanel );
}

/**
 * Moves the given panel to the center of the workspace/container
 */
function MediaGroupPanelManager_CenterOnContainer( imagePanel )
{
  if( imagePanel )
  {
    var dimensions = imagePanel.getDimensions();
    var x = (this.mContainer.getWidth() / 2) - (dimensions[0] / 2);
    var y = (this.mContainer.getHeight() / 2) - (dimensions[1] / 2);

    imagePanel.moveTo( x, y );
  }
}

/**
 * Closes all image panels by calling close on each ImagePanel
 */
function MediaGroupPanelManager_CloseAllImagePanels()
{
  var maxTimes = this.mImagePanels.length;
  while( this.mImagePanels.length > 0 && maxTimes >= 0  )
  {
    if( this.mImagePanels[ 0 ] )
      this.mImagePanels[ 0 ].close( true );

    maxTimes--;
  }
}

function MediaGroupPanelManager_CloseCurrentSlide( forceCurrentSlide )
{
  if( ( forceCurrentSlide != true ) &&
      ( this.mCurrentWorkingSlide ) &&
      ( this.mCurrentWorkingPresentation ) )
  {
    var imp = this;
    this.addPostSaveOperation( function(){ imp.closeCurrentSlide( true ); } );
    this.saveCurrentSlide();
    return;
  }

  this.mCurrentWorkingSlide = null;
  this.resetWorkspace();
  this.resizeWorkspace();
  this.updateHeader( '' );


}

function MediaGroupPanelManager_CloseCurrentPresentation( forceClosePresentation )
{
  if( ( forceClosePresentation != true ) &&
      ( this.mCurrentWorkingSlide ) &&
      ( this.mCurrentWorkingPresentation ) )
  {
    var imp = this;
    this.addPostSaveOperation( function(){ imp.closeCurrentPresentation( true ); } );
    this.saveCurrentSlide();
    return;
  }

  this.mCurrentWorkingSlide = null;
  this.mCurrentWorkingPresentation = null;
  this.resetWorkspace();
  this.resizeWorkspace();
  this.updateHeader( '' );


}

/**
 * Returns a valid starting postion (x,y) for the given image panel
 */
function MediaGroupPanelManager_GetStartingPosition( panel, startingX, startingY )
{
  var toReturn = new Array();
  if( Position.within( this.mContainer, startingX, startingY ) )
  {
    toReturn[ 0 ] = startingX;
    toReturn[ 1 ] = startingY;
  }
  else
  {
    toReturn[ 0 ] = 0;
    toReturn[ 1 ] = 0;
  }

  return toReturn;
}

/**
 * Gets the current image panel
 */
function MediaGroupPanelManager_GetCurrentImagePanel()
{
  // default to the first one, if we have any
  if( ! this.mCurrentImagePanel && ( this.mImagePanels.length > 0 ) )
  {
    this.setCurrentImagePanel( this.mImagePanels[ 0 ] );
  }

  return this.mCurrentImagePanel;
}

function MediaGroupPanelManager_GetImagePanelByIdentity( id )
{
  if( this.mImagePanels && ( this.mImagePanels.length > 0 ) )
  {
    for( var i = 0; i < this.mImagePanels.length; i++ )
    {
      if( this.mImagePanels[i] && this.mImagePanels[i].identity == id )
      {
        return this.mImagePanels[i];
      }
    }
  }

  //alert( "MediaGroupPanelManager_GetImagePanelByIdentity: " + id )
  return null;
}

function MediaGroupPanelManager_GetImagePanelByMediaId( mediaId )
{
  if( this.mImagePanels && ( this.mImagePanels.length > 0 ) )
  {
    for( var i = 0; i < this.mImagePanels.length; i++ )
    {
      if( this.mImagePanels[i].mediaInfo && this.mImagePanels[i].mediaInfo.id == mediaId )
      {
        return this.mImagePanels[i];
      }
    }
  }

  return null;
}

/**
 * Sets the given image panel as the currently selected one
 */
function MediaGroupPanelManager_SetCurrentImagePanel( imagePanel )
{
  if( imagePanel )
  {
    // set it as current panel
    this.mCurrentImagePanel = imagePanel;

    // update title
    this.updateHeader( this.mCurrentImagePanel.mediaInfo.displayTitle );

    // set focus on the current panel
    for( var i = 0; i < this.mImagePanels.length; i++ )
    {
      if( this.mImagePanels[i] == this.mCurrentImagePanel )
      {
        // current panel
        this.mCurrentImagePanel.setCurrentImagePanel( true );

        // bring to front
        this.bringToFront( this.mCurrentImagePanel );

        // update image panel info
        if( this.mMediaPanelInfo )
        {
          this.mMediaPanelInfo.setFieldValues( this.mImagePanels[ i ].mediaInfo.fieldValues );
        }

        // update panner
        if( this.mThumbnailPanner )
          this.mThumbnailPanner.setImagePanel( this.mImagePanels[ i ] );
      }
      else
      {
        // not current image panel
        this.mImagePanels[ i ].setCurrentImagePanel( false );
      }
    }
  }
  else
  {
    // no current image panel

    // clear header
    this.updateHeader( '' );

    // clear thumbnail panner
    if( this.mThumbnailPanner )
    {
      this.mThumbnailPanner.setImagePanel( null );
    }

    if( this.mMediaPanelInfo )
    {
      this.mMediaPanelInfo.setFieldValues( null );
    }
  }
}

/**
 * Sets the slides images object
 */
function MediaGroupPanelManager_SetSlidesPanel( slidesPanel )
{
  this.mSlidesPanel = slidesPanel;
}



/**
 * Sets the slides images object
 */
function MediaGroupPanelManager_SetImagesPanel( imagesPanel )
{
  this.mImagesPanel = imagesPanel;
}

function MediaGroupPanelManager_SetAnimate( animate )
{
  this.mAnimate = animate;
}

/**
 * Brings the given image panel to the front by chaning its z index
 */
function MediaGroupPanelManager_BringToFront( imagePanel )
{
  if( imagePanel )
  {
    var orderedImagePanel = [];
    orderedImagePanel[0] = imagePanel;
    orderedImagePanel[0].setStackOrder( this.mImagePanels.length );
    this.mImagePanels.without( imagePanel );
    for( var i = 0; i < this.mImagePanels.length; i++ )
    {
      if( this.mImagePanels[i] != imagePanel )
      {
        orderedImagePanel[i+1] = this.mImagePanels[i];
        orderedImagePanel[i+1].setStackOrder( this.mImagePanels.length - (i + 1) );
      }
    }

    // make sure they are ordered
    this.mImagePanels = orderedImagePanel.compact();
  }
}

/**
 * Updates the header with the given message.
 * It will include the current any current prsentaiton name
 * and/or slide currently being editied
 */
function MediaGroupPanelManager_UpdateHeader( message )
{
  if( this.mHeader )
  {
    if( ( ! message ) || ( message == null ) )
      message = '';

    // include presentation and slide info if we have it
    if( this.mCurrentWorkingPresentation || this.mCurrentWorkingSlide )
    {
      if( this.mCurrentWorkingPresentation &&
          this.mCurrentWorkingSlide &&
          this.mCurrentWorkingSlide.description &&
          this.mCurrentWorkingPresentation.displayName
          )
      {
        message =
          ' (' +
          ( this.getCurrentSlideIndex() + 1 ) +
          ' of ' + this.getCurrentTotalNumberOfSlides() +
          ') ' +
          this.mCurrentWorkingPresentation.displayName +
          ' - ' +
          this.mCurrentWorkingSlide.description +
          ': ' +
          message;
      }
      else if( this.mCurrentWorkingSlide && this.mCurrentWorkingSlide.description )
      {
        message =
          ' (' +
          ( this.getCurrentSlideIndex() + 1 ) +
          ' of ' + this.getCurrentTotalNumberOfSlides() +
          ') ' +
          this.mCurrentWorkingSlide.description +
          ': ' +
          message;
      }
      else if( this.mCurrentWorkingPresentation && this.mCurrentWorkingPresentation.displayName )
      {
        message =
          ' (' +
          ( this.getCurrentSlideIndex() + 1 ) +
          ' of ' + this.getCurrentTotalNumberOfSlides() +
          ') ' +
          this.mCurrentWorkingPresentation.displayName +
          ' - ' +
          message;
      }
    }

    var displayMessage = message;
    if( displayMessage.length > this.MAX_HEADER_MESSAGE_LENGTH )
    {
      displayMessage = displayMessage.substring( 0, this.MAX_HEADER_MESSAGE_LENGTH ) + '&#133;';
    }
    else if( displayMessage.length == 0 )
    {
      displayMessage = '&nbsp;';
    }



    this.mHeader.update( displayMessage );
    this.mHeader.title = message;
  }
}

function MediaGroupPanelManager_AddPostSaveOperation( someFunction )
{
  if( someFunction )
  {
    this.mPostSaveOperations.push( someFunction );
  }
}

function MediaGroupPanelManager_NotifySildeSaved()
{
  this.endLoadingState();

  if( ( this.mPostSaveOperations ) &&
      ( this.mPostSaveOperations.length > 0 ) )
  {
    for( var i = 0; i < this.mPostSaveOperations.length; i++ )
    {
      if( this.mPostSaveOperations[i] )
      {
        this.mPostSaveOperations[i].call();

        this.mPostSaveOperations[i] = null;
        this.mPostSaveOperations = this.mPostSaveOperations.compact();
      }
    }
  }
}

function MediaGroupPanelManager_ImagePanelChanged( imagePanel )
{
  if( imagePanel )
  {
    var currentImagePanel = this.getCurrentImagePanel();
    if( currentImagePanel == imagePanel )
    {
      if( this.mThumbnailPanner )
      {
        this.mThumbnailPanner.updatePanBox();
      }
    }

    // update controls, if any
    if( imagePanel.mControl )
    {
      imagePanel.mControl.positionControls();

      // update slider
      if( imagePanel.mControl.mSlider )
        imagePanel.mControl.mSlider.setValue( imagePanel.getLunaLevel(), false );
    }
  }
}

/**
 * Returns an array of Objects containing all needed information
 * to restore the state of the current workspace.
 */
function MediaGroupPanelManager_ConstructSlideImagesToSave()
{
  var slideImages = $( new Array() );
  var imagePanel;
  var slideImage;
  var position;
  var dimensions;
  var currentViewPoint;
  var identity = 1;
  for( var i = 0; i < this.mImagePanels.length; i++ )
  {
    imagePanel = this.mImagePanels[i];
    if( imagePanel )
    {
      // create object to pass to request update
      slideImage = new Object();
      slideImage.mediaId = imagePanel.mediaInfo.id;
      slideImage.slideId = 0;

      // give each slideImage and imagePanel a unique identity
      // so that we can refer to them later when scaling
      slideImage.identity = identity++;
      imagePanel.identity = slideImage.identity;

      // only include this if we have a working slide
      if( this.mCurrentWorkingSlide )
        slideImage.slideId = this.mCurrentWorkingSlide.id;

      if( imagePanel.isTemplatedPanel == true )
      {
        slideImage = Static_MediaGroupPanelManager_ConstructTemplatedPanelSaveObject( imagePanel, slideImage, this.mContainer );
      }
      else
      {
        slideImage = Static_MediaGroupPanelManager_ConstrcutImageSaveObject( imagePanel, slideImage, this.mContainer );
      }

      // add it to the list
      slideImages.push( slideImage );
    }
  }

  return slideImages;
}

/**
 * Updates the current state of the slide to the server
 */
function MediaGroupPanelManager_UpdateCurrentSlide()
{
  if( this.mFunctionRequestUpdateSlideImage )
  {
    if( ( this.mUpdatingSlideInProgress != true ) && this.mCurrentWorkingPresentation && this.mCurrentWorkingSlide )
    {
      // constrcut the stuff we are saving
      var slideImages = this.constructSlideImagesToSave();

      // mark our selves for saving
      this.mUpdatingSlideInProgress = true;

      // request an update
      this.mFunctionRequestUpdateSlideImage( slideImages );

      // store the last time we requested an update
      this.mUpdatingSlideTimeStamp = new Date();
    }
    else
    {
      this.mFunctionMessageToUser( jshConstrcutMockResponse( 'Unable to update slide images, no working presentation/slide set' ) );
    }
  }
  else
  {
    // cant save without save function so lets continue as before
    this.notifySildeSaved();
  }
}

/**
 * Marks the given slide as updated and ready to save slide
 */
function MediaGroupPanelManager_MarkSlideAsSaved()
{
  // see if its time to save
  this.saveCurrentSlide( true );
}

/**
 * Saves the current slide by updating all slide images then requesting a slide save
 */
function MediaGroupPanelManager_SaveCurrentSlide( saveOnly, finalAttempt )
{
  //debug( 'MediaGroupPanelManager_SaveCurrentSlide: saveOnly: ', saveOnly );
  if( this.mCurrentWorkingPresentation && this.mCurrentWorkingSlide )
  {
    // lets save update all sides to the server
    if( saveOnly != true )
    {
      // start the loading state
      this.startLoadingState();

      // update the slides to the server
      this.updateCurrentSlide();

      // now lets make sure we call our selves after the max timeout
      var maxTimeout = this.mTimeout * 2;
      var ipm = this;
      setTimeout(
        function(){ ipm.saveCurrentSlide( true, true ); },
        maxTimeout );
    }

    if( this.mUpdatingSlideInProgress == true )
    {
      //debug( 'this.mUpdatingSlideInProgress: ' + this.mUpdatingSlideInProgress );

      // make sure each image panel was udated
      var doSave = true;
      for( var i = 0; i < this.mImagePanels.length; i++ )
      {
        if( this.mImagePanels[i] && ( this.mImagePanels[i].successfullUpdated == false ) )
        {
          // a panel still hasnt been saved.  cant save yet
          doSave = false;
          break;
        }
      }

      // do we save?
      if( doSave )
      {
        //debug( 'SAVING  SLIDE!!!' );
        this.mFunctionRequestSaveSlide( this.mCurrentWorkingSlide.id );
        this.mUpdatingSlideInProgress = null;

        // reset panel flags
        for( var i = 0; i < this.mImagePanels.length; i++ )
        {
          this.mImagePanels[i].successfullUpdated = null;
        }
      }
      else if( finalAttempt == true )
      {
        // something happened and we could not savel
        this.mUpdatingSlideInProgress = null;
        this.endLoadingState();
        this.mFunctionMessageToUser( jshConstrcutMockResponse( 'Error occured and slide may not have been saved.  Please try again.' ) );
      }
    }
  }
  else
  {
    //this.mFunctionMessageToUser( jshConstrcutMockResponse( 'Unable to save slide, no working prsentation/slide set' ) );
  }
}

function MediaGroupPanelManager_GetCurrentTotalNumberOfSlides()
{
  if( this.mSlidesPanel && this.mSlidesPanel.mSlideInfos )
  {
    return this.mSlidesPanel.mSlideInfos.length;
  }

  return 0;
}

function MediaGroupPanelManager_GetCurrentSlideIndex()
{
  if( this.mCurrentWorkingSlide )
  {
    if( this.mSlidesPanel && this.mSlidesPanel.mSlideInfos )
    {
      for( var i = 0; i < this.mSlidesPanel.mSlideInfos.length; i++ )
      {
        if( this.mCurrentWorkingSlide.id == this.mSlidesPanel.mSlideInfos[i].id )
        {
          return i;
        }
      }
    }
  }

  return -1;
}

function MediaGroupPanelManager_GetCurrentSlide()
{
  return this.mCurrentWorkingSlide;
}

function MediaGroupPanelManager_GetCurrentPresentation()
{
  return this.mCurrentWorkingPresentation;
}

function MediaGroupPanelManager_SetCurrentPresentation( presentation )
{
  this.mCurrentWorkingPresentation = presentation;

 
  this.updateHeader( '' );
}

function MediaGroupPanelManager_GetCurrentWorkspaceRatio()
{
  return this.mCurrentRatio;
}

function MediaGroupPanelManager_ImageNotAvailableUrl( imageNotAvailableUrl )
{
  this.mImageNotAvailableUrl = imageNotAvailableUrl;
}

function MediaGroupPanelManager_SetFlashPlayerUrl( flashPlayerUrl )
{
  this.mFlashPlayerUrl = flashPlayerUrl;
}

function MediaGroupPanelManager_SetTemplateUrlPrefix( templateUrlPrefix )
{
  this.mTemplateUrlPrefix = templateUrlPrefix;
}

/**
 * Restores the workspace to the state defined within the given slide.  Any existing
 * image panels will be removed.
 *
 * Note: this method will prompt the user to confirm the restore since
 */
function MediaGroupPanelManager_RestoreWorkspace( slideInfo, presentationInfo, skipConfirmation, addControls, forceRestore )
{
  if( slideInfo )
  {
    // save before restoring
    if( ( forceRestore != true ) &&
        ( this.mCurrentWorkingPresentation && this.mCurrentWorkingSlide ) )
    {
      var ipm =  this;
      this.addPostSaveOperation( function(){ ipm.restoreWorkspace( slideInfo, presentationInfo, skipConfirmation, addControls, true ); } );
      this.saveCurrentSlide();
      return;
    }

    this.mCurrentWorkingPresentation = presentationInfo;
    this.mCurrentWorkingSlide = slideInfo;
    this.resetWorkspace();
    this.resizeWorkspace();
    this.updateHeader( '' );


    if( this.mThumbnailPanner )
      this.mThumbnailPanner.hide();

    //debug( jshObjectArrayToParamString( slideInfo.slideImages ) );

    var imagePanel;
    var slideImage;
    for( var i = 0; i < slideInfo.slideImages.length; i++ )
    {
      slideImage = slideInfo.slideImages[i];
      slideImage.mediaInfo = slideImage.media;

      // create panel and set values
      imagePanel = Static_MediaGroupPanelManager_ConstrcutMediaPanel( slideImage.mediaInfo, this, this.mPostResizeFunction, this.mPostDestoryFunction, addControls );
      imagePanel.slideImage = slideImage;

      // set identitys to both the slide images and the image panel
      // that way we can refer to then later when scaling.
      imagePanel.identity = i + 1;
      slideInfo.slideImages[i].identity = imagePanel.identity;

      // add and render it
      imagePanel.render( this.mContainer );

      // render control if we have one
      if( imagePanel.mControl )
      {
        if( this.mWindowingControlsOnly == true )
        {
          imagePanel.mControl.render( imagePanel );
        }
        else
        {
          imagePanel.mControl.render( imagePanel );
        }
      }

      this.addImagePanel( imagePanel, false );
    }

    this.rescaleWorkspace( slideInfo.slideImages );

    this.endLoadingState();
  }
  else
  {
    this.endLoadingState( true );
  }
}

function MediaGroupPanelManager_RestoreWorkspaceByIndex( index, skipConfirmationOnRestore, addControlsOnRestore )
{
  if( this.mSlidesPanel && this.mSlidesPanel.mSlideInfos )
  {
    if( this.mSlidesPanel.mSlideInfos[index] )
    {
      this.mSlidesPanel.restoreSlide( this.mSlidesPanel.mSlideInfos[index], this.getCurrentPresentation(), skipConfirmationOnRestore, addControlsOnRestore );
    }
  }
}

/**
 * Clears all image panels from the workspace without calling delete if we are currently
 * in the middle of editing a slide
 */
function MediaGroupPanelManager_ResetWorkspace()
{
  this.mResettingWorkspace = true;
  this.closeAllImagePanels();
  this.mResettingWorkspace = null;
}

/**
 * Resizes the workspace as to maximize its size to the window size while maintaining
 * the appropriate ratio.
 *
 * @param ratio optional value used to determin the optimal size of the workspace
 */
function MediaGroupPanelManager_ResizeWorkspace( ratio )
{
  var screenSize = jshGetWindowSize();
  if( this.mCurrentWorkingPresentation &&
    ( this.mCurrentWorkingPresentation.width > 0 ) &&
    ( this.mCurrentWorkingPresentation.height > 0 ) )
  {
    ratio = [ this.mCurrentWorkingPresentation.width, this.mCurrentWorkingPresentation.height ];
  }

  if( ratio )
    this.mCurrentRatio = ratio;

  if( !this.mCurrentRatio )
    this.mCurrentRatio = this.DEFAULT_WORKSPACE_SIZE;

  //debug( 'resize: ', this.mCurrentRatio );
  var size = jshCalculateProportionalDimensions( this.mCurrentRatio, screenSize );
  this.mContainer.style.width  = size[0] + 'px';
  this.mContainer.style.height = size[1] + 'px';

  // repsotion the panels, if any
  if( this.mSlidesPanel )
  {
    this.mSlidesPanel.reposition();
  }

  if( this.mImagesPanel )
  {
    this.mImagesPanel.reposition();
  }


}

/**
 * Given a previous state of the workspace in the form of an array of previous states
 * the current workspace is scaled appropriately as to preserve the composite
 */
function MediaGroupPanelManager_RescaleWorkspace( previousState )
{
  if( previousState && ( previousState.length > 0 ) )
  {
    var imagePanel;
    var derivedState;
    for( var i = 0; i < previousState.length; i++ )
    {
      imagePanel = this.getImagePanelByIdentity( previousState[i].identity );
      if( imagePanel )
      {
        previousState[i].mediaInfo = imagePanel.mediaInfo;
        previousState[i].imagePanel = imagePanel;
        derivedState = this.deriveImagePanelState( previousState[i] );

        // resize image panel already in workspace
        Static_MediaGroupPanelManager_RescaleImagePanelInWorkspace( imagePanel, derivedState );

        if( this.mThumbnailPanner )
        {
          this.mThumbnailPanner.moveToDefaultPosition();
        }

        if( this.mMediaPanelInfo )
        {
          this.mMediaPanelInfo.moveToDefaultPosition();
        }
      }
      else
      {
        //debug( 'no image by identity: ' + previousState[i].identity );
      }
    }

    // reorder the panels so they are in stack order
    this.mImagePanels.sort(
      function( a, b )
      {
        if( a.getStackOrder() == b.getStackOrder() )
          return 0;
        else if( a.getStackOrder() > b.getStackOrder() )
          return 1;

        return -1;

      } );
  }
}

function Static_MediaGroupPanelManager_RescaleImagePanelInWorkspace( imagePanel, derivedState )
{
  // luna media and full initialized external media we can
  // restore otherwise we have to wait
  if( imagePanel.isTemplatedPanel == true )
  {
    imagePanel.resize( derivedState.panelWidth, derivedState.panelHeight );
    imagePanel.moveTo( derivedState.positionX, derivedState.positionY );
    imagePanel.setStackOrder( derivedState.stackOrder );

    imagePanel.restoreFromState( derivedState );
  }
  else if( ( ( imagePanel.mInitialized == true ) ||
      ( imagePanel.mLunaSourceUrl != null ) ) )
  {
    // update the image panel with the new values
    imagePanel.resize( derivedState.panelWidth, derivedState.panelHeight );
    imagePanel.moveTo( derivedState.positionX, derivedState.positionY );
    imagePanel.setLunaLevel( derivedState.level, derivedState.centerPoint, null, derivedState.scaleFactor );
    imagePanel.setStackOrder( derivedState.stackOrder );
  }
  else
  {
    // call our selves in a bit until we are ready,
    // otherwise only a partial restore is done.
    var ip = imagePanel;
    var ds = derivedState;
    setTimeout( function(){Static_MediaGroupPanelManager_RescaleImagePanelInWorkspace( ip, ds ); }, 300 );
  }
}

function MediaGroupPanelManager_DeriveImagePanelState( previousState )
{
  var workspaceDimensions = [ this.mContainer.getWidth(), this.mContainer.getHeight() ];
  return Static_MediaGroupPanelManager_DeriveImagePanelState( previousState, workspaceDimensions );
}

/**
 * Does all the work of deriving image panel inforation ( dimensions, pan, postion, etc )
 * from a previous state to match the current workspace state.
 *
 *
 */
function Static_MediaGroupPanelManager_DeriveImagePanelState( previousState, workspaceDimensions )
{
  var deducedState = new Object();

  deducedState.positionX = 0;
  deducedState.positionY = 0;
  deducedState.panelWidth = 0;
  deducedState.panelHeight = 0;
  deducedState.workspaceWidth = 0;
  deducedState.workspaceHeight = 0;
  deducedState.centerPointX = 0;
  deducedState.centerPointY = 0;
  deducedState.centerPoint = [0,0];
  deducedState.actualImageSizeWidth = 0;
  deducedState.actualImageSizeHeight = 0;

  deducedState.level = 0;
  deducedState.scaleFactorX = 1;
  deducedState.scaleFactorY = 1;
  deducedState.scaleFactor = [];
  deducedState.stackOrder = -1;

  deducedState.identity = -1;

  if( previousState )
  {
    deducedState.identity = previousState.identity;

    deducedState.mediaInfo = previousState.mediaInfo;
    deducedState.imagePanel = previousState.imagePanel;

    deducedState.workspaceWidth = workspaceDimensions[0];
    deducedState.workspaceHeight = workspaceDimensions[1];

    deducedState.stackOrder = previousState.stackOrder;

    deducedState.positionX = Math.round( ( previousState.positionX / previousState.workspaceWidth ) * workspaceDimensions[0] );
    deducedState.positionY = Math.round( ( previousState.positionY / previousState.workspaceHeight ) * workspaceDimensions[1] );

    deducedState.panelWidth = Math.round( ( previousState.panelWidth / previousState.workspaceWidth ) * workspaceDimensions[0] );
    deducedState.panelHeight = Math.round( ( previousState.panelHeight / previousState.workspaceHeight ) * workspaceDimensions[1] );

    deducedState.actualImageSizeWidth = Math.round( ( previousState.actualImageSizeWidth / previousState.workspaceWidth ) * workspaceDimensions[0] );
    deducedState.actualImageSizeHeight = Math.round( ( previousState.actualImageSizeHeight / previousState.workspaceHeight ) * workspaceDimensions[1] );

    if( ( previousState.centerPointX >= 0 ) && ( previousState.centerPointY >= 0 ) )
    {
      deducedState.centerPointX = Math.round( ( previousState.centerPointX / previousState.actualImageSizeWidth ) * deducedState.actualImageSizeWidth );
      deducedState.centerPointY = Math.round( ( previousState.centerPointY / previousState.actualImageSizeHeight ) * deducedState.actualImageSizeHeight );

      deducedState.centerPoint[0] = deducedState.centerPointX;
      deducedState.centerPoint[1] = deducedState.centerPointY;
    }

    deducedState.previousState = previousState;

    if( previousState.mediaInfo && previousState.mediaInfo.maxWidth && previousState.mediaInfo.maxHeight )
    {
      var ais = deducedState.actualImageSizeWidth;
      var longSide = previousState.mediaInfo.maxWidth;
      if( previousState.mediaInfo.maxHeight > previousState.mediaInfo.maxWidth  )
      {
        ais = deducedState.actualImageSizeHeight;
        longSide = previousState.mediaInfo.maxHeight;
      }

      // cal the level rounding to the nearest int taking advantage that Luna levels always comes in halves from the max side, ie power of 2.
      // Solving for level L where ( maxSide / 2^L ) = actualImageSize
      // using logs  to solve for L
      // ( maxSide / actualImageSize ) = 2^L
      //  ln( maxSide / actualImageSize ) = L*ln(2)
      // ( ln( maxSide / actualImageSize ) / ln(2) ) = L
      deducedState.level = Math.round( Math.log( longSide / ais  ) / Math.LN2 );

      //debug( 'longSide: ', longSide, ' ; ais: ', ais, ' ; ', (Math.round( Math.log( longSide / ais  ) / Math.LN2 )) );

      // now that we have the level lets cal the scale factor
      deducedState.scaleFactorX = ( ( deducedState.actualImageSizeWidth * Math.pow( 2, deducedState.level ) ) / previousState.mediaInfo.maxWidth );
      deducedState.scaleFactorY = ( ( deducedState.actualImageSizeHeight * Math.pow( 2, deducedState.level ) ) / previousState.mediaInfo.maxHeight );
      deducedState.scaleFactor[0] = deducedState.scaleFactorX;
      deducedState.scaleFactor[1] = deducedState.scaleFactorY;
    }
    else if( deducedState.imagePanel )
    {
      deducedState.imagePanel.mMaximizeOnLoad = false;
      deducedState.imagePanel.deducedState = deducedState;
      if( deducedState.imagePanel.mInitialized )
      {
        var ais = deducedState.actualImageSizeWidth;
        var longSide = deducedState.imagePanel.mBaseRatio[0];
        if( deducedState.imagePanel.mBaseRatio[1] > deducedState.imagePanel.mBaseRatio[0]  )
        {
          ais = deducedState.actualImageSizeHeight;
          longSide = deducedState.imagePanel.mBaseRatio[1];
        }

        // cal the level rounding to the nearest int
        // assume no scale factor ( ie 1 )
        deducedState.level = Math.round( Math.LN2 * Math.log( longSide / ais  ) );
        deducedState.level = Math.min( deducedState.level, ( Static_ImagePanel_EXTERNAL_ADDITIONAL_LEVELS + Static_ImagePanel_EXTERNAL_MEDIA_STARTING_LEVEL ) )
        deducedState.level = Math.max( 0, deducedState.level );

        // now that we have the level lets cal the scale factor
        deducedState.scaleFactorX = ( ( deducedState.actualImageSizeWidth * Math.pow( 2, deducedState.level ) ) / deducedState.imagePanel.mBaseRatio[0] );
        deducedState.scaleFactorY = ( ( deducedState.actualImageSizeHeight * Math.pow( 2, deducedState.level ) ) / deducedState.imagePanel.mBaseRatio[1] );
        deducedState.scaleFactor[0] = deducedState.scaleFactorX;
        deducedState.scaleFactor[1] = deducedState.scaleFactorY;
      }
    }
  }

  //debug( 'Ipm:' + ' ; ' + deducedState.position + ' ; ' + deducedState.scaleFactor + ' ; ' + deducedState.pan + ' ; ' + deducedState.dimensions + ' ; ' + workspaceDimensions );

  return deducedState;
}

/**
 * Creates a new image panel given the image info
 */
function MediaGroupPanelManager_CreateImagePanel( mediaInfo, startingX, startingY )
{
  var panel = Static_MediaGroupPanelManager_ConstrcutMediaPanel( mediaInfo, this, this.mPostResizeFunction, this.mPostDestoryFunction );
  if( panel && ( ! mediaInfo.urlSource ) )
  {
    panel.mMaximizeOnLoad = true;
  }

  // add and render it
  // move the image to the center of the workspace
  var position = this.getStartingPosition( panel, startingX, startingY );
  panel.render( this.mContainer, position[0], position[1] );
  panel.maximizePanelToImage();
  this.addImagePanel( panel );

  // if we dont get back a starting position
  // default to center on workspace
  if( !( position && position[0] && position[1] ) )
  {
    panel.centerOnContainer();
  }

  // render control if we have one
  if( panel.mControl )
  {
    panel.mControl.render( panel );
  }

  // make it the current
  this.setCurrentImagePanel( panel );
  this.bringToFront( panel );

  return panel;
}

/**
 * the given image panel is added to those being managed and sets it as the current
 * image panel.
 */
function MediaGroupPanelManager_AddImagePanel( imagePanel )
{
  if( imagePanel )
  {
    this.mImagePanels.push( imagePanel );
    this.setCurrentImagePanel( imagePanel );
  }

  return imagePanel;
}

/**
 * Removes the given image panel and if we are currently editing a slide and we are
 * not resetting the workspace a request to detel the slide image is sent.
 */
function MediaGroupPanelManager_RemoveImagePanel( imagePanel )
{
  if( imagePanel )
  {
    var indexOfPanel = this.indexOfPanel( imagePanel );
    this.mImagePanels[ indexOfPanel ] = null;
    this.mImagePanels = this.mImagePanels.compact();

    // are we removing the current panel?
    if( imagePanel == this.mCurrentImagePanel )
      this.mCurrentImagePanel = null;

    this.setCurrentImagePanel( this.getCurrentImagePanel() );
  }
}

/**
 * Starts the loadings state
 */
function MediaGroupPanelManager_StartLoadingState()
{
  if( this.mLoading != true )
  {
    var dimensions = jshGetWindowSize();
    this.mLoadingContainer.style.width = ( dimensions[0] )  + 'px';
    this.mLoadingContainer.style.height = ( dimensions[1] ) + 'px';

    this.mLoading = true;
    this.mLoadingStartTime = new Date();
    this.mLoadingContainer.show();

    // make sure we ultimately hide the loading screen
    var maxTimeout = ( this.mTimeout + 100 );
    var ipm = this;
    setTimeout( function(){ ipm.endLoadingState() }, maxTimeout );
  }
}

/**
 * Ends the loading state
 */
function MediaGroupPanelManager_EndLoadingState( forceClose )
{
  // close if enough time has elapsed or if we are told to
  if( ( forceClose == true ) ||
      ( ( this.mLoadingStartTime - new Date() ) > this.MIN_LOADING_TIME ) )
  {
    // stop the loading process
    if( this.mLoading != null )
    {
      this.mLoading = null;
      this.mLoadingStartTime = null;
      this.mLoadingContainer.hide();
    }
  }
  else
  {
    // make sure we dont just flash, give us a few before remving our selves
    var timeout = this.MIN_LOADING_TIME - ( this.mLoadingStartTime - new Date() );
    timeout = Math.min( timeout, this.MIN_LOADING_TIME );

    // call our selves in a bit
    var ipm = this;
    setTimeout( function(){ ipm.endLoadingState( true ) }, timeout );
  }
}

function MediaGroupPanelManager_ShowHelpPage()
{
  openHelp( this.mHelpUrl );
}

function MediaGroupPanelManager_ShowMessageToUser( message )
{
  if( this.mFunctionMessageToUser )
  {
    this.mFunctionMessageToUser( jshConstrcutMockResponse( message ) );
  }
  else
  {
    alert( 'msg: ' + message );
  }
}

function Static_MediaGroupPanelManager_CurrentActionHasChanged( control, oldAction, newAction )
{
  if( control && control.mManager )
  {
    if( control.mManager.getCurrentImagePanel() )
    {
      var manager = control.mManager;
      var imagePanel = manager.getCurrentImagePanel();

      imagePanel.currentActionHasChanged( newAction );

      if( control.ACTION_RESET == newAction  )
      {
        imagePanel.reset();
        control.setAction( oldAction );
      }
    }
  }
}

function Static_MediaGroupPanelManager_CacnelCurrentAction( control )
{
  if( control && control.mManager )
  {
    var manager = control.mManager;

    // pass along to panels
    if( manager.mSlidesPanel )
    {
      manager.mSlidesPanel.endCurrentAction( true );
    }

    if( manager.mImagesPanel )
    {
      manager.mImagesPanel.endCurrentAction( true );
    }

    // do we have an image panel currently?
    var imagePanel = manager.getCurrentImagePanel();
    if( imagePanel )
    {
      //pass along cancel request
      imagePanel.endCurrentAction( true );
    }
  }
}
function Static_MediaGroupPanelManager_ConstrcutMediaPanel( mediaInfo, manager, postResizeFunction, postDestoryFunction, addControls )
{
  if( mediaInfo )
  {
    if( mediaInfo.video == true )
    {
      return Static_MediaGroupPanelManager_ConstrcutVideoPanel( mediaInfo, manager, postResizeFunction, postDestoryFunction, addControls );
    }
  }

  // default to image panel
  return Static_MediaGroupPanelManager_ConstrcutImagePanel( mediaInfo, manager, postResizeFunction, postDestoryFunction, addControls );
}


function Static_MediaGroupPanelManager_ConstrcutImagePanel( mediaInfo, manager, postResizeFunction, postDestoryFunction, addControls )
{
  var panel = new ImagePanel( postResizeFunction, postDestoryFunction );
  panel.setManager( manager );

  if( !mediaInfo )
  {
    panel.mediaInfo = {};
    panel.setIgnoreSizeConstraints( true );
    panel.setThumbnailUrl( manager.mImageNotAvailableUrl );
    panel.setLunaLevel = function(){ /*do nothing*/ };

    if( addControls != false )
    {
      panel.setControl( new OnImagePanelControls( manager, Static_MediaGroupPanelManager_CurrentActionHasChanged, Static_MediaGroupPanelManager_CacnelCurrentAction ) );
      panel.mControl.setManager( manager );
      panel.mControl.setAnimate( manager.mAnimate );

      panel.mSkipClose = true;
      panel.mSkipInfoPanel = true;
      panel.mSkipThumbnailPanel = true;
    }
  }
  else
  {
    panel.setBaseRatio( mediaInfo.maxWidth, mediaInfo.maxHeight );
    panel.setMaxLunaLevel( mediaInfo.maxLevel );
    panel.setLunaLevel( panel.getDefaultLevel() );
    panel.setIgnoreSizeConstraints( true );

    if( addControls != false )
    {
      panel.setControl( new OnImagePanelControls( manager, Static_MediaGroupPanelManager_CurrentActionHasChanged, Static_MediaGroupPanelManager_CacnelCurrentAction ) );
      panel.mControl.setManager( manager );
      panel.mControl.setAnimate( manager.mAnimate );

      panel.mSkipClose = true;
      panel.mSkipInfoPanel = true;
      panel.mSkipThumbnailPanel = true;
    }

    panel.setLunaSourceUrl( mediaInfo.urlSource );
    panel.setConfirmBeforeClose( false );

    // make sure the field values are jsonfied, if any
    panel.mediaInfo = mediaInfo;
    if( mediaInfo.fieldValues )
    {
      mediaInfo.fieldValues = jshEvalJSON( mediaInfo.fieldValues, 1 );
    }

    // low res image
    // if its doesnt have url source then sets all of the know images,
    // then set the low res
    if( ( mediaInfo.urlSource == null ) &&
        ( mediaInfo.fullImageUrls != null ) )
    {
      panel.setFullImageUrls( jshEvalJSON( mediaInfo.fullImageUrls, 1 ) );

      // External Media to open the smallest size in workspace
      //panel.setThumbnailUrl( mediaInfo.fullImageUrls[0] );

      /** Older version that grabbed the largest size possible
      * May need to revert back to this.
      */
      // figure out the right size
      if( ( panel.mFullImageUrls.length > 3 ) &&
          ( panel.mFullImageUrls[3] != null ) &&
          ( panel.mFullImageUrls[3].length > 0 ) )
      {
        // lets grab size 4 if available
        panel.setThumbnailUrl( panel.mFullImageUrls[3] );
      }
      else
      {
        // must have an image smaller than a 3 so lets just grab the largest
        panel.setThumbnailUrl( mediaInfo.largestUrlAvailable );
      }
    }
    else
    {
      // grab the largest know
      panel.setThumbnailUrl( mediaInfo.largestUrlAvailable );
    }
  }

  return panel;
}

function Static_MediaGroupPanelManager_ConstrcutVideoPanel( mediaInfo, manager, postResizeFunction, postDestoryFunction, addControls )
{
  var panel = new TemplatedPanel( postResizeFunction, postDestoryFunction );
  panel.setTemplateUrlPrefix( manager.mTemplateUrlPrefix );
  panel.setManager( manager );
  panel.setFlashPlayerUrl( manager.mFlashPlayerUrl );

  if( !mediaInfo )
  {
    panel.mediaInfo = {};

    if( addControls != false )
    {
      panel.setControl( new TemplatedPanelControls( manager, Static_MediaGroupPanelManager_CurrentActionHasChanged, Static_MediaGroupPanelManager_CacnelCurrentAction ) );
      panel.mControl.setManager( manager );
      panel.mControl.setAnimate( manager.mAnimate );

      panel.mControl.mSkipSlider = true;
      panel.mControl.mSkipThumbnailPanel = true;
      panel.mControl.mSkipForceFitToFrame = true;
    }
  }
  else
  {
    if( addControls != false )
    {
      panel.setControl( new TemplatedPanelControls( manager, Static_MediaGroupPanelManager_CurrentActionHasChanged, Static_MediaGroupPanelManager_CacnelCurrentAction ) );
      panel.mControl.setManager( manager );
      panel.mControl.setAnimate( manager.mAnimate );

      panel.mControl.mSkipSlider = true;
      panel.mControl.mSkipThumbnailPanel = true;
      panel.mControl.mSkipForceFitToFrame = true;
    }

    panel.setSourceUrl( mediaInfo.urlSource );
    panel.setConfirmBeforeClose( false );

    // make sure the field values are jsonfied, if any
    panel.mediaInfo = mediaInfo;
    if( mediaInfo.fieldValues )
    {
      mediaInfo.fieldValues = jshEvalJSON( mediaInfo.fieldValues, 1 );
    }
  }

  return panel;
}

function Static_MediaGroupPanelManager_ConstrcutImageSaveObject( imagePanel, saveObject, workspace )
{
  if( !saveObject )
  {
    saveObject = {};
  }

  var position = imagePanel.getPosition();
  saveObject.positionX = position[0];
  saveObject.positionY = position[1];

  var dimensions = imagePanel.getDimensions();
  saveObject.panelWidth = ( dimensions[0] );
  saveObject.panelHeight = ( dimensions[1] );

  saveObject.workspaceWidth = workspace.getWidth();
  saveObject.workspaceHeight = workspace.getHeight();

  var currentViewPoint = [0,0];
  if( imagePanel.isTemplatedPanel )
  {
    currentViewPoint = [0,0];
  }
  else
  {
    currentViewPoint = imagePanel.getCurrentViewPoint();
  }

  saveObject.centerPointX = ( currentViewPoint[0] );
  saveObject.centerPointY = ( currentViewPoint[1] );

  saveObject.actualImageSizeWidth = imagePanel.mImage.width;
  saveObject.actualImageSizeHeight = imagePanel.mImage.height;

  saveObject.stackOrder = imagePanel.getStackOrder();

  return saveObject;
}

function Static_MediaGroupPanelManager_ConstructTemplatedPanelSaveObject( templatedPanel, saveObject, workspace )
{
  if( !saveObject )
  {
    saveObject = {};
  }

  var position = templatedPanel.getPosition();
  saveObject.positionX = position[0];
  saveObject.positionY = position[1];

  var dimensions = templatedPanel.getDimensions();
  saveObject.panelWidth = ( dimensions[0] );
  saveObject.panelHeight = ( dimensions[1] );

  saveObject.workspaceWidth = workspace.getWidth();
  saveObject.workspaceHeight = workspace.getHeight();

  saveObject.stackOrder = templatedPanel.getStackOrder();

  saveObject.isTemplatedPanel = true;

  if( templatedPanel.getAdditionalSaveAttributes )
  {
    var attributes = templatedPanel.getAdditionalSaveAttributes();
    saveObject.templateAttributes = attributes;
  }

  return saveObject;
}



