<?php

/**
 * Controller is the customized base controller class.
 * All controller classes for this application should extend from this base class.
 */
class Controller extends CController
{

  /**
   *
   * @var string the default layout for the controller view. Defaults to '//layouts/column1',
   *      meaning using a single column layout. See 'protected/views/layouts/column1.php'.
   */
  public $layout = '//layouts/main';

  /**
   *
   * @var array context menu items. This property will be assigned to {@link CMenu::items}.
   */
  public $menu = array ();

  /**
   *
   * @var array the breadcrumbs of the current page. The value of this property will
   *      be assigned to {@link CBreadcrumbs::links}. Please refer to {@link CBreadcrumbs::links}
   *      for more details on how to specify this property.
   */
  public $breadcrumbs = array ();

  /**
   * Runs an action with the specified filters.
   * Extends the CController::runActionWithFilters() function.
   * If a Guest user is trying to access a non-public page, then redirect to the login page.
   *
   * @param CAction $action
   *          the action to be executed.
   * @param array $filters
   *          list of filters to be applied to the action.
   */
  public function runActionWithFilters($action, $filters)
  {
    $route = strtolower ( "{$this->id}/{$action->id}" );
    $params = app ()->params;
    // se la manutenzione è attivata e non sono un debugger e non sono già nella pagina di manutenzione
    if (! MaintenanceModeController::userCanSee () && $route != "maintenancemode/index" && $route != "session/login")
    {
      // vado alla pagina di manutenzione
      $this->redirectTo ( "maintenancemode/index" );
      return;
    }
    elseif (! MaintenanceModeController::maintenanceModeEnabled () && $route == "maintenancemode/index")
    {
      $this->redirectTo ( "/" );
      return;
    }
    
    $ppr = array_get ( $_REQUEST, PublicPageRequest::KEY );
    $pprOk = PublicPageRequest::instance ()->remove ( $ppr );
    
    if (isset ( $params ) && isset ( $params ['publicPages'] ))
    {
      $publicPages = array ();
      foreach ( $params ['publicPages'] as $pp )
        $publicPages [] = strtolower ( $pp );
      
      if (! user ()->tryLogin () && user ()->isGuest && ! in_array ( $route, $publicPages ) && ! $pprOk)
      {
        $routeStart = strtolower ( "{$this->id}/*" );
        if (user ()->isGuest && ! in_array ( $routeStart, $publicPages ))
        {
          user ()->loginRequired ();
          return;
        }
      }
    }
    parent::runActionWithFilters ( $action, $filters );
  }

  /**
   * permette di loggare tutte le azione dell'utente ed, eventualmente, di inviarle a terzi
   *
   * @param CAction $action          
   */
  protected function logUserAction(CAction $action)
  {
    $actionPath = strtolower ( "$this->id/$action->id" );
    $actionWild = strtolower ( "$this->id/*" );
    $doLog = false;
    
    $logActions = new CArray ( paramdeep ( 'security', 'logActions' ) );
    
    $logActionsSpecific = $logActions->specific;
    if (is_array_ex ( $logActionsSpecific, true ))
    {
      if (array_values_exist ( $logActionsSpecific, array (
          $actionPath,
          $actionWild 
      ), true ))
      {
        $doLog = true;
      }
    }
    else
    {
      $logActionsBypass = $logActions->bypass;
      if (is_array_ex ( $logActionsBypass ) && ! array_values_exist ( $logActionsBypass, array (
          $actionPath,
          $actionWild 
      ), true ))
      {
        $doLog = true;
      }
    }
    if ($doLog)
    {
      $data = array ();
      if (array_values_exist ( $logActions->requestData, array (
          $actionPath,
          $actionWild 
      ), true ))
        $data ['request'] = $_REQUEST;
      security_log ( $actionPath, 'actions', false, $data );
    }
  }

  protected function afterAction($action)
  {
    $bread = $this->breadcrumbs;
    if ($bread != null && is_array ( $bread ))
    {
      $newBread = array ();
      foreach ( $bread as $key => $value )
      {
        $newBread [t ( $key )] = $value;
      }
      $this->breadcrumbs = $newBread;
    }
    return parent::afterAction ( $action );
  }

  /**
   *
   * @param CAction $action          
   */
  protected function beforeAction($action)
  {
    $this->applyIpFilter ();
    $this->extendsUserWorkPeriod ();
    $this->logUserAction ( $action );
    
    return parent::beforeAction ( $action );
  }

  protected function applyIpFilter()
  {
    $filter = new CArray ( paramdeep ( 'security', 'ipFilter' ) );
    
    if (! $filter->enabled)
      return;
    
    $ip = $_SERVER ['REMOTE_ADDR'];
    
    $isAllowed = null;
    $isDenied = null;
    
    if (count ( $filter->allow ) > 0)
    {
      $isAllowed = false;
      foreach ( $filter->allow as $allowed )
      {
        if (fnmatch ( $allowed, $ip ))
        {
          $isAllowed = true;
          break;
        }
      }
    }
    else
    {
      $isAllowed = true;
    }
    
    if (count ( $filter->deny ) > 0)
    {
      $isDenied = false;
      foreach ( $filter->deny as $denied )
      {
        if (fnmatch ( $denied, $ip ))
        {
          $isDenied = true;
          break;
        }
      }
    }
    else
    {
      $isDenied = false;
    }
    
    $fail = false;
    
    if ($filter->allowOverDeny)
    {
      if ($isAllowed)
        $fail = false;
      elseif ($isDenied)
        $fail = true;
    }
    else
    {
      if ($isDenied)
        $fail = true;
      elseif ($isAllowed)
        $fail = false;
    }
    
    if ($fail)
    {
      $message = "user=" . (user ()->name) . "(id=" . user ()->id . ") from $_SERVER[REMOTE_ADDR]:$_SERVER[REMOTE_PORT] has not passed IP FILTERS";
      access_denied_check ( null, true, $message, $message );
    }
  }

  protected function extendsUserWorkPeriod()
  {
    if (Yii::app ()->user->isGuest)
      return;
    
    $openPeriod = null;
    $openPeriods = WorkPeriod::model ()->byUser ( Yii::app ()->user->model )
      ->open ()
      ->findAll ();
    
    if (count ( $openPeriods ) > 1)
    {
      /** @var WorkPeriod[] $openPeriods */
      $openPeriods = array_sort ( $openPeriods, function ($x, $y)
      {
        $ty = new DateTimeEx ( $x->login_at );
        $tx = new DateTimeEx ( $y->login_at );
        return $tx->compare ( $ty );
      } );
      
      /** @var WorkPeriod $lastWp */
      $lastWp = array_first ( $openPeriods );
      
      foreach ( $openPeriods as $wp )
        if ($wp instanceof WorkPeriod && $wp->id != $lastWp->id)
        {
          $wp->last_action_at = DateTimeEx::nows ();
          $wp->closed = 1;
          $wp->update ( array (
              'last_action_at',
              'closed' 
          ) );
        }
      
      $openPeriod = $lastWp;
    }
    else if (count ( $openPeriods ) == 0)
      Yii::app ()->user->logout ();
    else
      $openPeriod = $openPeriods [0];
    
    if ($openPeriod != null)
      $openPeriod->refresh ();
  }

  protected function findModel($class, $id, $primaryKey = null)
  {
    if (isset ( $primaryKey ))
      $model = $class::model ()->find ( "$primaryKey = :id", array (
          ':id' => $id 
      ) );
    else
      $model = $class::model ()->findByPk ( $id );
    
    if ($model === null)
      throw new CHttpException ( 404, Yii::t ( 'app', 'The request page does not exists for {class}.', array (
          '{class}' => $class 
      ) ) );
    
    return $model;
  }

  protected function ensurePresenceOfParams(array $requiredParams, array $params)
  {
    foreach ( $requiredParams as $requiredParam )
      if (! isset ( $params [$requiredParam] ) || strlen ( $params [$requiredParam] ) == 0)
        throw new CHttpException ( 400, Yii::t ( 'app', 'Parameter {requiredParam} is required.', array (
            '{requiredParam}' => $requiredParam 
        ) ) );
    
    return true;
  }

  public function getActionParamsforLog()
  {
    return $_REQUEST; // $_GET + $_POST;
  }

  public function getAbsoluteUrl(array $mergeThis = array(), $usePost = false)
  {
    $params = $usePost ? $_POST : $_GET;
    if ($mergeThis != null && is_array ( $mergeThis ))
      $params = array_merge ( $params, $mergeThis );
    return absoluteUrl ( $this->route, $params );
  }

  public function renderBookmark($obj, $return = false)
  {
    if ($obj == null)
      return null;
    $data = $obj->getBookmarkData ();
    return $this->renderPartial ( "/shared/_bookmarkIcon", array (
        "hasBookmark" => $data->self_book,
        "id_reference" => $data->self_id,
        "type" => $data->self_type 
    ), $return );
  }

  /**
   * render partial html/text
   *
   * @param string $html          
   * @param bool $return
   *          (default false)
   * @param bool $partial
   *          (default true)
   * @return string|NULL
   */
  public function renderHtml($html, $return = false, $partial = true)
  {
    if ($partial)
      return $this->renderPartial ( '/shared/_html', array (
          'html' => $html 
      ), $return );
    else
      return $this->render ( '/shared/_html', array (
          'html' => $html 
      ), $return );
  }

  public function renderFile($viewFile, $data = null, $return = false)
  {
    $content = parent::renderFile ( $viewFile, $data, $return );
    if (DebugController::isInDebugMode () && paramdeep ( 'debug', 'showViewLink' ))
    {
      $content = $content . CHtml::link ( '<span class="icon-wrench"></span>', url ( 'debug/viewAsText', array (
          'filename' => $viewFile 
      ) ), array (
          'title' => $viewFile 
      ) );
    }
    return $content;
  }

  public function renderTable($title, $icon, $columns, $rows, $restHtml = null, $return = false)
  {
    $this->render ( '//shared/_table', array (
        'title' => $title,
        'icon' => $icon,
        'columns' => $columns,
        'rows' => $rows,
        'restHtml' => $restHtml 
    ), $return );
  }

  public function renderTablePartial($columns, $rows, $return = false)
  {
    $this->renderPartial ( '//shared/_tablePartial', array (
        'columns' => $columns,
        'rows' => $rows 
    ), $return );
  }

  public function renderVideoJW($source, $width, $height, $autoplay = false)
  {
    $this->widget ( 'ext.jwplayer.JwPlayer', array (
        'flvName' => $source,
        'width' => $width,
        'height' => $height,
        'autoStart' => $autoplay 
    ) );
  }

  /**
   *
   * @param string|array $source
   *          array('src'=>URL, 'type'=>TYPE) where TYPE: video/ogg | video/mp4 | video/webm
   * @param int $width
   *          (default NULL)
   * @param int $height
   *          (default NULL)
   * @param bool $controls
   *          (default true)
   * @param bool $autoplay
   *          (default false)
   * @param bool $loop
   *          (default true)
   * @param string $poster
   *          (default NULL) url
   * @param string $preload
   *          (default NULL) auto|metadata|none
   * @param bool $return
   *          (default false)
   * @return string|NULL
   */
  public function renderVideo($source, $width = null, $height = null, $controls = true, $autoplay = false, $loop = true, $poster = null, $preload = null, $return = false)
  {
    $tagId = "vid_" . rand ( 1, 1000000 );
    
    if (is_array ( $source ))
    {
      if (array_key_exists ( 'src', $source ))
        $source = array (
            $source 
        );
    }
    else if (is_string ( $source ))
    {
      $source = array (
          'src' => $source 
      );
      $source = array (
          $source 
      );
    }
    else
      return null;
    
    $beginTag = "<video id=\"$tagId\"";
    if ($controls)
      $beginTag .= " controls";
    if ($autoplay)
      $beginTag .= " autoplay";
    if ($loop)
      $beginTag .= " loop";
    if (! empty ( $poster ))
      $beginTag .= " poster=\"$poster\"";
    if (! empty ( $preload ))
      $beginTag .= " preload=\"$preload\"";
    if (! empty ( $width ))
      $beginTag .= " width=\"$width\"";
    if (! empty ( $height ))
      $beginTag .= " height=\"$height\"";
    $beginTag .= ">";
    
    $videos = array ();
    foreach ( $source as $item )
    {
      if (array_key_exists ( 'type', $item ))
        $videos [] = "<source src=\"$item[src]\" type=\"$item[type]\">";
      else
        $videos [] = "<source src=\"$item[src]\">";
    }
    
    $errorMessage = t ( "Your browser does not support the video tag." );
    
    $endTag = "</video>";
    
    $html = implode ( PHP_EOL, array (
        $beginTag,
        implode ( PHP_EOL, $videos ),
        $errorMessage,
        $endTag 
    ) );
    
    if (paramdeep ( 'video', 'enabledRefreshDivButton' ))
    {
      $script = "<script>
      $('#button_$tagId').click(function()
      {
      var code = $('#wrapper_$tagId').html();
      $('#wrapper_$tagId').html('');
      $('#wrapper_$tagId').html(code);
    });
    </script>";
      
      $html = "<div id=\"wrapper_$tagId\">$html</div><a id=\"button_$tagId\" href=\"#\"><span class=\"icon-refresh\"></span></a>" . $script;
    }
    
    return $this->renderHtml ( $html, $return );
  }

  /**
   * to be called before render
   *
   * @param string $url          
   * @param string $seconds          
   */
  public function redirectTimed($url, $seconds)
  {
    script ()->registerMetaTag ( "$seconds;url={$url}", null, 'refresh' );
  }

  /**
   *
   * @param string $nationality          
   * @return boolean true if the flag has been printed
   */
  public function printCountryFlag($nationality)
  {
    $obj = new stdClass ();
    $obj->result = false;
    $this->renderPartial ( '/shared/_nationality', array (
        'nationality' => $nationality,
        'obj' => $obj 
    ) );
    return $obj->result;
  }

  public function printPopupLink($html, $url, $title = null, array $htmlOptions = array(), array $options = array())
  {
    if (empty ( $options ['height'] ))
      $options ['height'] = 500;
    if (empty ( $options ['width'] ))
      $options ['width'] = 800;
    if (empty ( $options ['top'] ))
      $options ['top'] = 50;
    if (empty ( $options ['left'] ))
      $options ['left'] = 50;
    
    if (! empty ( $title ))
      $htmlOptions ['title'] = $title;
    
    $this->renderPartial ( '/shared/_popupLink', array (
        'html' => $html,
        'url' => $url,
        'htmlOptions' => $htmlOptions,
        'options' => $options 
    ) );
  }

  public function printMenu($title, array $items, $return = false)
  {
    $this->renderPartial ( '/shared/_genericMenu', array (
        'title' => $title,
        'items' => $items 
    ), $return );
  }

  /**
   *
   * @param string $route          
   * @param array $params
   *          default=array()
   * @param bool $terminate
   *          default=true
   * @param number $statusCode
   *          default=302
   */
  public function redirectTo($route, array $params = array(), $terminate = true, $statusCode = 302)
  {
    $this->redirect ( url ( $route, $params ), $terminate, $statusCode );
  }

  public function redirectToSelf($keepParams = false)
  {
    $controller = $this->id;
    $action = $this->action->id;
    $params = $keepParams ? $_REQUEST : array ();
    $this->redirectTo ( "{$controller}/{$action}", $params );
  }

  /**
   * (non-PHPdoc)
   *
   * @see CController::redirect()
   */
  public function redirect($url, $terminate = true, $statusCode = 302)
  {
    parent::redirect ( $url, $terminate, $statusCode );
  }

  public function printMenuSimple($title, array $items, $return = false)
  {
    $itemsEx = array ();
    foreach ( $items as $name => $url )
    {
      $itemsEx [] = array (
          'label' => $name,
          'url' => $url 
      );
    }
    return $this->printMenu ( $title, $itemsEx, $return );
  }

  public function getPageLink(array $mergeThis = array())
  {
    return $this->getAbsoluteUrl ( $mergeThis );
  }

  public function calculateCoord($originalWidth, $width, $x, $scale)
  {
    $scaleX = $width / $originalWidth;
    $x = ( int ) ($scaleX * $x);
    
    $centerX = ($width / 2);
    
    $x = ($centerX - $x) * $scale;
    
    return $x;
  }

  public function printAutozoomImageScaleByWidth($url, $originalWidth, $originalHeight, $width, $x, $y, $scale = 2, $speed = 0.3, $return = false, $options = array())
  {
    $height = ( int ) ImageHelper::findScaledHeight ( $originalWidth, $originalHeight, $width );
    
    $x = $this->calculateCoord ( $originalWidth, $width, $x, $scale );
    $y = $this->calculateCoord ( $originalHeight, $height, $y, $scale );
    
    return $this->printAutozoomImage ( $url, $width, $height, $x, $y, $scale, $speed, $return, $options );
  }

  public function printAutozoomImageScaleByHeight($url, $originalWidth, $originalHeight, $height, $x, $y, $scale = 2, $speed = 0.3, $return = false, $options = array())
  {
    $width = ( int ) ImageHelper::findScaledWidth ( $originalWidth, $originalHeight, $height );
    
    $x = $this->calculateCoord ( $originalWidth, $width, $x, $scale );
    $y = $this->calculateCoord ( $originalHeight, $height, $y, $scale );
    
    return $this->printAutozoomImage ( $url, $width, $height, $x, $y, $scale, $speed, $return, $options );
  }

  public function printAutozoomImage($url, $width, $height, $x, $y, $scale = 2, $speed = 0.3, $return = false, $options = array())
  {
    $imageId = rand ( 1, 100000 );
    
    $options = implode ( ' ', array_map_kv ( $options, function ($k, $v)
    {
      return "$k=\"$v\"";
    } ) );
    
    $imageCode = "
  
    <style>
  
    #wrapper_$imageId
    {
    width: {$width}px;
    height: {$height}px;
    border: 1px solid black;
    overflow: hidden;
    position: relative;
  }
  
  #image_$imageId
  {
  background-image: url('$url');
  background-size: {$width}px {$height}px;
  background-position: center;
  transition: all {$speed}s ease-in-out;
  width: 100%;
  height: 100%;
  transform: scale(1);
  -webkit-transform: scale(1);
  position: relative;
  left: 0;
  top: 0;
  }
  
  #wrapper_$imageId:hover #image_$imageId
  {
  transform: scale($scale);
  -webkit-transform: scale($scale);
  left: {$x}px;
  top: {$y}px;
  }
  
  </style>
  
  <div id='wrapper_$imageId' $options><div id='image_$imageId'></div></div>
  ";
    
    /*
     * $imageCode = "
     * <style>
     * .imgzoom_$imageId
     * {
     * width: {$width}px;
     * -webkit-transition: all .2s ease-in-out;
     * -moz-transition: all .2s ease-in-out;
     * -o-transition: all .2s ease-in-out;
     * -ms-transition: all .2s ease-in-out;
     *
     * -webkit-transform: scale(1);
     * -moz-transform: scale(1);
     * -o-transform: scale(1);
     * transform: scale(1);
     * }
     *
     *
     * .imgzoom_$imageId:hover
     * {
     * -webkit-transform: scale($scale);
     * -moz-transform: scale($scale);
     * -o-transform: scale($scale);
     * transform: scale($scale);
     * overflow: hidden;
     * }
     * </style>
     * <img class=\"imgzoom_$imageId\" src=\"$url\"/>
     *
     * ";
     */
    
    // $imageCode .= "[$width,$height,$x,$y]";
    
    return $this->renderHtml ( $imageCode, $return );
  }

  public function printAutozoomReverseImageScaleByWidth($url, $originalWidth, $originalHeight, $width, $x, $y, $scale = 2, $speed = 0.3, $return = false, $options = array())
  {
    $height = ( int ) ImageHelper::findScaledHeight ( $originalWidth, $originalHeight, $width );
    
    $x = $this->calculateCoord ( $originalWidth, $width, $x, $scale );
    $y = $this->calculateCoord ( $originalHeight, $height, $y, $scale );
    
    return $this->printAutozoomReverseImage ( $url, $width, $height, $x, $y, $scale, $speed, $return, $options );
  }

  public function printAutozoomReverseImageScaleByHeight($url, $originalWidth, $originalHeight, $height, $x, $y, $scale = 2, $speed = 0.3, $return = false, $options = array())
  {
    $width = ( int ) ImageHelper::findScaledWidth ( $originalWidth, $originalHeight, $height );
    
    $x = $this->calculateCoord ( $originalWidth, $width, $x, $scale );
    $y = $this->calculateCoord ( $originalHeight, $height, $y, $scale );
    
    return $this->printAutozoomReverseImage ( $url, $width, $height, $x, $y, $scale, $speed, $return, $options );
  }

  public function printAutozoomReverseImage($url, $width, $height, $x, $y, $scale = 2, $speed = 0.3, $return = false, $options = array())
  {
    $imageId = rand ( 1, 100000 );
    
    $options = implode ( ' ', array_map_kv ( $options, function ($k, $v)
    {
      return "$k=\"$v\"";
    } ) );
    
    $imageCode = "
  
    <style>
  
    #wrapper_$imageId
    {
    width: {$width}px;
    height: {$height}px;
    border: 1px solid black;
    overflow: hidden;
    position: relative;
  }
  
  #image_$imageId
  {
  transform: scale($scale);
  -webkit-transform: scale($scale);
  left: {$x}px;
  top: {$y}px;
  
  background-image: url('$url');
  background-size: {$width}px {$height}px;
  background-position: center;
  width: 100%;
  height: 100%;
  position: relative;
  
  }
  
  #wrapper_$imageId:hover #image_$imageId
  {
  background-image: url('$url');
  background-size: {$width}px {$height}px;
  background-position: center;
  transition: all {$speed}s ease-in-out;
  width: 100%;
  height: 100%;
  transform: scale(1);
  -webkit-transform: scale(1);
  position: relative;
  left: 0;
  top: 0;
  }
  
  </style>
  
  <div id='wrapper_$imageId' $options><div id='image_$imageId'></div></div>
  ";
    
    /*
     * $imageCode = "
     * <style>
     * .imgzoom_$imageId
     * {
     * width: {$width}px;
     * -webkit-transition: all .2s ease-in-out;
     * -moz-transition: all .2s ease-in-out;
     * -o-transition: all .2s ease-in-out;
     * -ms-transition: all .2s ease-in-out;
     *
     * -webkit-transform: scale(1);
     * -moz-transform: scale(1);
     * -o-transform: scale(1);
     * transform: scale(1);
     * }
     *
     *
     * .imgzoom_$imageId:hover
     * {
     * -webkit-transform: scale($scale);
     * -moz-transform: scale($scale);
     * -o-transform: scale($scale);
     * transform: scale($scale);
     * overflow: hidden;
     * }
     * </style>
     * <img class=\"imgzoom_$imageId\" src=\"$url\"/>
     *
     * ";
     */
    
    // $imageCode .= "[$width,$height,$x,$y]";
    
    return $this->renderHtml ( $imageCode, $return );
  }

  /**
   *
   * @param string $queryTag          
   * @param string[] $items          
   * @param bool $return          
   * @return string
   */
  public function addSuggestionsScript($queryTag, $items, $return = false)
  {
    if (empty ( $queryTag ))
      return null;
    
    if ($items == null || ! is_array ( $items ) || count ( $items ) <= 0)
      return null;
    
    $items = array_map_kv ( $items, function ($k, $v)
    {
      return "\"" . str_replace ( "\"", "\\\"", $v ) . "\"";
    } );
    
    $data = implode ( ',', $items );
    
    $script = "
      <script>
      $(function() {
      var availableTags = [$data];
      $( \"$queryTag\" ).autocomplete({
      source: availableTags
  });
  });
  </script>
  ";
    return $this->renderHtml ( $script, $return );
  }

  /**
   * return an array of uploaded files
   *
   * @return FileUpload[]
   */
  public function getUploadedFiles()
  {
    $files = array ();
    foreach ( $_FILES as $file => $info )
    {
      $fu = new FileUpload ();
      $fu->key = $name;
      foreach ( $info as $infoKey => $infoValue )
        $fu->$infoKey = $infoValue;
      $files [$file] = $fu;
    }
    return $files;
  }

  /**
   * return the first uploaded file
   *
   * @param string $key
   *          optional specify the key of the $_FILES array
   * @return FileUpload
   */
  public function getUploadedFile($key = null)
  {
    foreach ( $this->getUploadedFiles () as $name => $upload )
      if ($key === null || $key == $name)
        return $upload;
    return null;
  }

  /**
   *
   * @param mixed $condition          
   * @param string $error
   *          Translated error string
   * @return boolean
   */
  public function checkError($condition, $error)
  {
    if ($condition)
    {
      return true;
    }
    else
    {
      user ()->setFlash ( 'error', $error );
      return false;
    }
  }

  public function dragonImage($urls, $divWidth = null, $divHeight = null, array $dragonOptions = array(), array $divOptions = array())
  {
    $divStyle = array_get ( $divOptions, 'style', '' );
    
    if ($divWidth !== null)
    {
      if (ctype_digit ( $divWidth ))
        $divWidth = "{$divWidth}px";
      $divStyle .= " width: {$divWidth};";
    }
    
    if ($divHeight !== null)
    {
      if (ctype_digit ( $divHeight ))
        $divHeight = "{$divHeight}px";
      $divStyle .= " height: {$divHeight};";
    }
    
    if (! isEmptyOrWhitespace ( $divStyle ))
      $divOptions ['style'] = $divStyle;
    
    $id = uniqidex ( 'openseadragon_' );
    $divOptions ['id'] = $id;
    
    if (! is_array ( $urls ))
      $urls = array (
          $urls 
      );
    
    $isSingleImage = count ( $urls ) == 1;
    
    $dragonOptions = new JSObject ( $dragonOptions );
    $dragonOptions->excludeBrackets = false;
    
    $dragonOptions->add ( 'id', $id );
    $dragonOptions->add ( 'prefixUrl', request ()->baseUrl . '/images/openseadragon/' );
    
    if (! $isSingleImage)
    {
      $dragonOptions->add ( 'sequenceMode', true );
      $dragonOptions->add ( 'showNavigator', true );
      $dragonOptions->add ( 'showReferenceStrip', true );
      $dragonOptions->add ( 'preserveViewport', true );
      // $dragonOptions->add ( 'referenceStripScroll', 'vertical' );
    }
    
    foreach ( $urls as $urlIndex => $urlValue )
    {
      $tile = $dragonOptions->addArray ( 'tileSources' )
        ->addObject ( $urlIndex );
      if (is_array ( $urlValue ))
      {
        foreach ( $urlValue as $urlSubKey => $urlSubValue )
          $tile->add ( $urlSubKey, $urlSubValue );
      }
      else
      {
        $tile->add ( 'type', 'image' );
        $tile->add ( 'url', $urlValue );
      }
    }
    
    $divAttrs = CHtml::renderAttributes ( $divOptions );
    
    $script = new StringWriter ();
    $script->writeline ( '<div ' . $divAttrs . '></div>' );
    $script->writeline ( '<script type="text/javascript">' );
    $script->writeline ( "OpenSeadragon( $dragonOptions );" );
    $script->writeline ( '</script>' );
    
    echo ($script);
    
    return $id;
  }
}
