<?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 ?: 1);
        $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);
        Yii::log("\t Coordinate X \t".($x)." ", "info", "controller.printAutozoomReverseImageScaleByHeight");
        Yii::log("\t Coordinate Y \t".($y)." ", "info", "controller.printAutozoomReverseImageScaleByHeight");
        $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 #dddddd;
    overflow: hidden;
    position: relative;
    border-radius:5px;
    margin-top: 10px;
  }
  
  #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 dragonImageSingle($urls, $divWidth = null, $divHeight = null, array $dragonOptions = array(), array $divOptions,$pointX, $pointY) {

        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', false);
            $dragonOptions->add('showReferenceStrip', false);
            $dragonOptions->add('preserveViewport', true);
            $dragonOptions->add('showHomeControl', false);
            $dragonOptions->add('autoHideControls', false);
            // $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);
                $tile->add('buildPyramid', false);
                $pieces = explode('/', $urlValue);
                $more_pieces = explode('?', $pieces[count($pieces) - 1]);
                $mediaId = $more_pieces[0];
                $currentMedia = MediaAttachment::model()->findByPk($mediaId);
                $tile->add('isGenerated', $currentMedia->isGenerated());
                $tile->add('isSelectable', $currentMedia->isSelectable($deviceType));
                $tile->add('isSelected', false);
                $tile->add('hasNewCroppedData', false);
                $tile->add('croppingType', $currentMedia->getCroppingType());
                $tile->add('sectionGroup', $currentMedia->getSectionGroup($deviceType));
                $tile->add('description', $currentMedia->getSmallDescription($deviceType));
                $currentId = $tile->values['sectionGroup'] . "-" . $tile->values['croppingType'];
                $tile->add('parsedId', $mediaId);
                $thumbUrl[$currentId."-".$mediaId] = $urlValue;
                $tile->add('croppedAreaPresent', 0);
                $tile->add('croppedX', -1);
                $tile->add('croppedY', -1);
                $tile->add('croppedWidth', -1);
                $tile->add('croppedHeight', -1);
                if (!$alreadyFoundSelectedArray[$currentId] && $currentMedia->isSelectable($deviceType) && $photoAreSelectable == 1) {
                    //check if this is selected
                    $selectedCriteria = new CDbCriteria();
                    $selectedCriteria->condition = "image_id = $mediaId";
                    $foundImageRoi = ImagesRoi::model()->find($selectedCriteria);
                    if (isset($foundImageRoi)) {
                        $alreadyFoundSelectedArray[$currentId] = true;
                        if ($foundImageRoi->action == "crop") {
                            $tile->values['isSelected'] = true;
                            $tile->values['croppedAreaPresent'] = 1;
                            $tile->values['croppedX'] = $foundImageRoi->roi_x;
                            $tile->values['croppedY'] = $foundImageRoi->roi_y;
                            $tile->values['croppedWidth'] = $foundImageRoi->roi_width;
                            $tile->values['croppedHeight'] = $foundImageRoi->roi_height;
                        }
                    }
                }
            }
            if (!$alreadyFoundSelected) {
                $selectedIndex++;
            }
        }
        if (!$alreadyFoundSelected) {
            $selectedIndex = -1;
        }
        
        $divAttrs = CHtml::renderAttributes($divOptions);

        $basePath = Yii::app()->request->baseUrl;

        $selectedImagePath = "$basePath/images/openseadragon/selectimage_selected.png";
        $groupImagePath = "$basePath/images/openseadragon/selectimage_grouphover.png";
        $restImagePath = "$basePath/images/openseadragon/selectimage_rest.png";
        $hoverImagePath = "$basePath/images/openseadragon/selectimage_hover.png";
        $downImagePath = "$basePath/images/openseadragon/selectimage_pressed.png";
        
        $script = new StringWriter ();

        $scriptToWrite = <<<EOT
        <div $divAttrs>
    
        </div>
        <script>
            OpenSeadragon.setString("Tooltips.FullPage","Schermo intero");
                       
            viewer1 = OpenSeadragon( $dragonOptions );
            
            viewer1.addHandler("open", function(event){
                
                var pointXY = event.eventSource.viewport.imageToViewportCoordinates($pointX,$pointY);
                event.eventSource.viewport.zoomTo(9,pointXY,true);
                event.eventSource.viewport.panTo(pointXY);
                
            });
            

             
        </script>
            
EOT;

        $script->writeline($scriptToWrite);

        echo ($script);
        //file_put_contents("C:/Users/n.gasbarro/Desktop/OpenSeaDragon/index2.html",$script->buffer);

        return $id;
    }
    

    /**
     * dragonImageObscure
     * The function provide a new kind of selection. It show a DragonImage widget able to select an image and set an overlay rect.
     * Then, send to EventController/dragonImageObscureChangeXML an XMLHttpRequest POST with the rect position and the selected image id.
     * 
     * @param urls
     * @param divWidth
     * @param divHeight
     * @param dragonOptions
     * @param divOptions
     */
    public function dragonImageObscure($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', false);
            $dragonOptions->add('showReferenceStrip', false);
            $dragonOptions->add('preserveViewport', true);
            $dragonOptions->add('showHomeControl', false);
            $dragonOptions->add('showFullPageControl', false);
            $dragonOptions->add('autoHideControls', false);
        }

        //every gate belongs to a group, and the pictures are divided accordingly
        //every gate can have a selected pic and / or a cropped one
        //image attributes: selectable, croppable(?), sectionGroup, id, generated, description
        //selectable: the image might be selected
        //croppable: the image might be cropped (it's a plate)
        //group: the group of the image, meaning the device it belongs to
        //id: the db ID
        //generated: this field indicates that the images was generated by cropping, i.e. doesn't exists yet outside the viewer
        //description: a little description to help discern the images from one another (first device plate, second device face #1, ecc)
       
        $deviceType = Yii::app()->params['deviceType'];
       //$deviceType='ztl';
        $alreadyFoundSelectedArray = array();
        switch ($deviceType) {
            case "section":
                $alreadyFoundSelectedArray["first-plate-bw"] = false;
                $alreadyFoundSelectedArray["second-plate-bw"] = false;
                $alreadyFoundSelectedArray["first-face"] = false;
                $alreadyFoundSelectedArray["second-face"] = false;
                break;
            default:
                break;
        }
        $photoAreSelectable = isset(Yii::app()->params['photoEditingMode']) && Yii::app()->params['photoEditingMode'] !== "none" ? 1 : 0;
        
        
        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);
                $tile->add('buildPyramid', false);
                $pieces = explode('/', $urlValue);
                $more_pieces = explode('?', $pieces[count($pieces) - 1]);
                $mediaId = $more_pieces[0];
                $currentMedia = MediaAttachment::model()->findByPk($mediaId);
                $tile->add('isGenerated', $currentMedia->isGenerated());
                $tile->add('isSelectable', $currentMedia->isSelectable($deviceType));
                $tile->add('isSelected', false);
                $tile->add('hasNewCroppedData', false);
                $tile->add('croppingType', $currentMedia->getCroppingType());
                $tile->add('sectionGroup', $currentMedia->getSectionGroup($deviceType));
                $tile->add('description', $currentMedia->getSmallDescription($deviceType));
                $currentId = $tile->values['sectionGroup'] . "-" . $tile->values['croppingType'];
                $tile->add('parsedId', $mediaId);
                //$thumbUrl[$currentId."-".$mediaId] = $urlValue;
                $tile->add('croppedAreaPresent', 0);
                $tile->add('croppedX', -1);
                $tile->add('croppedY', -1);
                $tile->add('croppedWidth', -1);
                $tile->add('croppedHeight', -1);
                if (!$alreadyFoundSelectedArray[$currentId] && $currentMedia->isSelectable($deviceType) && $photoAreSelectable == 1) {
                    $thumbUrl[$currentId."-".$mediaId] = $urlValue;
                    //check if this is selected
                    $selectedCriteria = new CDbCriteria();
                    $selectedCriteria->condition = "image_id = $mediaId";
                    $foundImageRoi = ImagesRoi::model()->find($selectedCriteria);
                    if (isset($foundImageRoi)) {
                        $alreadyFoundSelectedArray[$currentId] = true;
                        if ($foundImageRoi->action == "crop") {
                            $tile->values['isSelected'] = true;
                            $tile->values['croppedAreaPresent'] = 1;
                            $tile->values['croppedX'] = $foundImageRoi->roi_x;
                            $tile->values['croppedY'] = $foundImageRoi->roi_y;
                            $tile->values['croppedWidth'] = $foundImageRoi->roi_width;
                            $tile->values['croppedHeight'] = $foundImageRoi->roi_height;
                        }
                    }
                }else{$thumbUrl[$currentId."-crop-".$mediaId] = $urlValue;$crop_Exist=true;}
            }
            if (!$alreadyFoundSelected) {
                $selectedIndex++;
            }
        }
        if (!$alreadyFoundSelected) {
            $selectedIndex = -1;
        }
        $divAttrs = CHtml::renderAttributes($divOptions);
        $basePath = Yii::app()->request->baseUrl;
        $imgPath = new JSObject();
        $imgPath->add('selectedImagePath',$basePath.'/images/openseadragon/selectimage_selected.png');
        $imgPath->add('groupImagePath',$basePath.'/images/openseadragon/selectimage_grouphover.png');
        $imgPath->add('restImagePath',$basePath.'/images/openseadragon/selectimage_rest.png');
        $imgPath->add('hoverImagePath',$basePath.'/images/openseadragon/selectimage_hover.png');
        $imgPath->add('downImagePath',$basePath.'/images/openseadragon/selectimage_pressed.png');
        $imgPath->add('basePath',$basePath);
        

        
        $script = new StringWriter ();

        $scriptToWrite = <<<EOT
        <div $divAttrs>
            <input id='selectedFrame' type='hidden' value='$selectedIndex'/>
            <style>
                .navigator .highlight{
                    opacity:    0.4;
                    filter:     alpha(opacity=40);
                    outline:    2px solid #900;
                    background-color: #900;
                }
                .highlight{
                    opacity:    0.4;
                    filter:     alpha(opacity=40);
                    outline:    12px auto #f89406;
                    background-color: white;
                }
                .highlight:hover, .highlight:focus{
                    filter:     alpha(opacity=70);
                    opacity:    0.7;
                    background-color: transparent;
                }
                #osd-filter-gamma{
                    direction: rtl
                }
            </style>
        </div>                                        
                        
        <script>
        dragonImageObscure($dragonOptions, $imgPath);
        </script>
EOT;

        $script->writeline($scriptToWrite);

        echo ($script);

        return $id;
    }

    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', false);
            $dragonOptions->add('showReferenceStrip', false);
            $dragonOptions->add('preserveViewport', true);
            $dragonOptions->add('showHomeControl', false);
            $dragonOptions->add('showFullPageControl', false);
            $dragonOptions->add('autoHideControls', false);
        

            // $dragonOptions->add ( 'referenceStripScroll', 'vertical' );
        }

        //every gate belongs to a group, and the pictures are divided accordingly
        //every gate can have a selected pic and / or a cropped one
        //image attributes: selectable, croppable(?), sectionGroup, id, generated, description
        //selectable: the image might be selected
        //croppable: the image might be cropped (maybe it's a face, maybe a plate)
        //group: the group of the image, meaning the device it belongs to
        //id: the db ID
        //generated: this field indicates that the images was generated by cropping, i.e. doesn't exists yet outside the viewer
        //description: a little description to help discern the images from one another (first device plate, second device face #1, ecc)
        $deviceType = Yii::app()->params['deviceType'];
        $alreadyFoundSelectedArray = array();
        switch ($deviceType) {
            case "section":
                $alreadyFoundSelectedArray["first-plate-bw"] = false;
                $alreadyFoundSelectedArray["second-plate-bw"] = false;
                $alreadyFoundSelectedArray["first-face"] = false;
                $alreadyFoundSelectedArray["second-face"] = false;
                break;
            default:
                break;
        }
        //$photoAreSelectable = isset(Yii::app()->params['photoEditingMode']) && Yii::app()->params['photoEditingMode'] !== "none" ? 1 : 0;
        $photoAreSelectable = Yii::app()->params['photoEditingMode'] === "facecrop" && Yii::app()->params['photoEditingMode'] !== "none" ? 1 : 0;
        $thumbUrl = array();
        $crop_Exist=false;
        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);
                $tile->add('buildPyramid', false);
                $pieces = explode('/', $urlValue);
                $more_pieces = explode('?', $pieces[count($pieces) - 1]);
                $mediaId = $more_pieces[0];
                $currentMedia = MediaAttachment::model()->findByPk($mediaId);
                $tile->add('isGenerated', $currentMedia->isGenerated());
                $tile->add('isSelectable', $currentMedia->isSelectable($deviceType));
                $tile->add('isSelected', false);
                $tile->add('hasNewCroppedData', false);
                $tile->add('croppingType', $currentMedia->getCroppingType());
                $tile->add('sectionGroup', $currentMedia->getSectionGroup($deviceType));
                $tile->add('description', $currentMedia->getSmallDescription($deviceType));
                $currentId = $tile->values['sectionGroup'] . "-" . $tile->values['croppingType'];
                $tile->add('parsedId', $mediaId);
                //$thumbUrl[$currentId."-".$mediaId] = $urlValue;
                $tile->add('croppedAreaPresent', 0);
                $tile->add('croppedX', -1);
                $tile->add('croppedY', -1);
                $tile->add('croppedWidth', -1);
                $tile->add('croppedHeight', -1);
                if (!$alreadyFoundSelectedArray[$currentId] && $currentMedia->isSelectable($deviceType) && $photoAreSelectable == 1) {
                    $thumbUrl[$currentId."-".$mediaId] = $urlValue;
                    //check if this is selected
                    $selectedCriteria = new CDbCriteria();
                    $selectedCriteria->condition = "image_id = $mediaId";
                    $foundImageRoi = ImagesRoi::model()->find($selectedCriteria);
                    if (isset($foundImageRoi)) {
                        $alreadyFoundSelectedArray[$currentId] = true;
                        if ($foundImageRoi->action == "crop") {
                            $tile->values['isSelected'] = true;
                            $tile->values['croppedAreaPresent'] = 1;
                            $tile->values['croppedX'] = $foundImageRoi->roi_x;
                            $tile->values['croppedY'] = $foundImageRoi->roi_y;
                            $tile->values['croppedWidth'] = $foundImageRoi->roi_width;
                            $tile->values['croppedHeight'] = $foundImageRoi->roi_height;
                        }
                    }
                }else{$thumbUrl[$currentId."-crop-".$mediaId] = $urlValue;$crop_Exist=true;}
            }
            if (!$alreadyFoundSelected) {
                $selectedIndex++;
            }
        }
        if (!$alreadyFoundSelected) {
            $selectedIndex = -1;
        }
        if($photoAreSelectable){
        $svg_matrix = '<svg id="414b524a-ee5f-4f6c-8765-78965914da1d" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 766 231" style="margin-top:18px;margin-bottom: 29px;">
        <defs>
            <style>
                
                .txt-font{font-size:14px;font-family:ArialMT, Arial;}
                .no-fill{fill:none;}
                
                </style>
        </defs>
        <path id="plate-bw" class="shape-error stroke-error" d="M212,21V7a5.1,5.1,0,0,0-5-5H46a5.1,5.1,0,0,0-5,5V21Z"/>
        <path id="face" class="shape-error stroke-error" d="M765,21V7a5.1,5.1,0,0,0-5-5H233a5.1,5.1,0,0,0-5,5V21Z"/>
        <text id="face-txt" class="txt-font txt-error" transform="translate(415 16.5)">Driver Documentation</text>
        <text id="plate-bw-txt" class="txt-font txt-error" transform="translate(85 16.5)">Line Crossing</text>

        <path id="first-plate-bw" class="shape-error stroke-error" d="M212,22v87a5,5,0,0,1-5,5H46a5,5,0,0,1-5-5V22Z"/>
        <path id="first-face" class="shape-error stroke-error" d="M765,22v87a5,5,0,0,1-5,5H233a5,5,0,0,1-5-5V22Z"/>
        <rect id="second-plate-bw" class="shape-error stroke-error" x="41.5" y="130" width="169" height="92" rx="5" ry="5"/>
        <rect id="second-face"class="shape-error stroke-error" x="228" y="130" width="537" height="92" rx="5" ry="5"/>
        
        <path id="first" class="shape-error stroke-error" d="M30.8,22H6a5.2,5.2,0,0,0-5,5.4v89.2A5.2,5.2,0,0,0,6,122H30.8Z"/>
        <text id="first-txt" class="txt-font txt-error" transform="matrix(0, -1.01, 1, 0, 20.79, 110.92)">Start Section</text>
        <line id="first-line" class="no-fill stroke-error" x1="30.8" y1="122" x2="765" y2="121.5"/>
        <path id="second" class="shape-error stroke-error" d="M30.8,130H6a5.2,5.2,0,0,0-5,5.4v89.2A5.2,5.2,0,0,0,6,230H30.8Z"/>
        <text id="second-txt" class="txt-font txt-error" transform="matrix(0, -1.01, 1, 0, 20.79, 217.42)">End Section</text>
        <line id="second-line" class="no-fill stroke-error" x1="30.8" y1="230" x2="765" y2="229.5"/>
    ';

        
        $thumbHtml = "";
        
        $total_thumb=0;
        //ToDO -- if Behaviour set images's position 
        $img_matrix_pos8x8 = array(
            array('X'=>"61",'Y'=>"36.5",'pos'=>'first-plate','free'=>true),
            array('X'=>"248",'Y'=>"25.5",'pos'=>'first-face','free'=>true),
            array('X'=>"431",'Y'=>"25.5",'pos'=>'first-face','free'=>true),
            array('X'=>"614",'Y'=>"25.5",'pos'=>'first-face','free'=>true),
            array('X'=>"61",'Y'=>"142.5",'pos'=>'second-plate','free'=>true),
            array('X'=>"248",'Y'=>"133.5",'pos'=>'second-face','free'=>true),
            array('X'=>"431",'Y'=>"133.5",'pos'=>'second-face','free'=>true),
            array('X'=>"614",'Y'=>"133.5",'pos'=>'second-face','free'=>true)
        );

        //ToDO Check Image Type
        
        foreach($thumbUrl as $key => $thumb){
            
            $key_exploded = explode("-",$key);
            $position=0;
            if(!in_array("crop", $key_exploded)){
            $position = array_search($key_exploded[0].'-'.$key_exploded[1],$img_matrix_pos8x8);
            for($pos=0;$pos < sizeof($img_matrix_pos8x8); $pos++){

                if(($img_matrix_pos8x8[$pos]['pos'] == $key_exploded[0].'-'.$key_exploded[1]) && $img_matrix_pos8x8[$pos]['free']){
                    $position = $pos;
                    $img_matrix_pos8x8[$pos]['free']=false;
                    break;
                }

            }
            
            $thumbHtml .=  '<g>
                <foreignObject id="thumb-selector-'.$key_exploded[count($key_exploded)-1].'" class="node" x="'.$img_matrix_pos8x8[$position]['X'].'" y="'.$img_matrix_pos8x8[$position]['Y'].'" width="130" height="62">
             
                    <div style=" position: relative;top: 0;left: 0; width:130px;" data-picture-type="'.$keys.'" >
                      <a class="thumbnail" onclick="navigatorById(\''.$key_exploded[count($key_exploded)-1].'\')">
                          <img src="'.$thumb.'" style="border-radius:4px;width:100px;position: relative;top: 0;left: 0;">
                      </a>
                    </div>
                </foreignObject>
                            </g>';
            $total_thumb++;
            }
        }

       if($crop_Exist && Yii::app()->params['photoEditingMode'] !== "none"){
        $checkMatrixJSonReload.='<script>$(document).ready(function(){checkMatrix.onReloadEvent()});</script>';
        }
        $thumbHtml = $svg_matrix . $thumbHtml . '</svg>';
    }else{
        $thumbHtml="";
        $total_thumb=0;
    }
        $divAttrs = CHtml::renderAttributes($divOptions);

        $basePath = Yii::app()->request->baseUrl;

        $selectedImagePath = "$basePath/images/openseadragon/selectimage_selected.png";
        $groupImagePath = "$basePath/images/openseadragon/selectimage_grouphover.png";
        $restImagePath = "$basePath/images/openseadragon/selectimage_rest.png";
        $hoverImagePath = "$basePath/images/openseadragon/selectimage_hover.png";
        $downImagePath = "$basePath/images/openseadragon/selectimage_pressed.png";
        
        $script = new StringWriter ();

        $scriptToWrite = <<<EOT
        $checkMatrixJSonReload
        <div $divAttrs>
            <input id='selectedFrame' type='hidden' value='$selectedIndex'/>
            <style>
                .navigator .highlight{
                    opacity:    0.4;
                    filter:     alpha(opacity=40);
                    outline:    2px solid #900;
                    background-color: #900;
                }
                .highlight{
                    opacity:    0.4;
                    filter:     alpha(opacity=40);
                    outline:    12px auto #f89406;
                    background-color: white;
                }
                .highlight:hover, .highlight:focus{
                    filter:     alpha(opacity=70);
                    opacity:    0.7;
                    background-color: transparent;
                }
                #osd-filter-gamma{
                    direction: rtl
                }
            </style>
        </div>
        $thumbHtml
                                        
                        
        <script>
       
            OpenSeadragon.setString("Tooltips.FullPage","Full Screen");
            OpenSeadragon.setString("Tooltips.SelectionToggle","Open Face Selection");
            OpenSeadragon.setString("Tooltips.SelectionConfirm","Selection Confirm");
            OpenSeadragon.setString("Tooltips.ImageTools","Image Adjustments");
            OpenSeadragon.setString("Tool.brightness","Brightness");
            OpenSeadragon.setString("Tool.contrast","Contrast");
            OpenSeadragon.setString("Tool.gamma","Gamma");
            OpenSeadragon.setString("Tool.reset","Reset");
            OpenSeadragon.setString("Tool.close","Save");
           
            viewer = OpenSeadragon( $dragonOptions );
            var overlaysMap={};
            var rectanglesMap={};
            var filterValues={};
            var listenerAdded=false; 
            var brightnessDefaultValue=0; 
            var contrastDefaultValue=1; 
            var gammaDefaultValue=1; 
            var brightnessminValue=-255;
            var brightnessMaxValue=255;
            var contrastMinValue=0;
            var contrastMaxValue=5;
            var gammaMinValue=0;
            var gammaMaxValue=2;
            var croppedImagesDataObject=[];
           
            var selectImageButton = new OpenSeadragon.Button({
                tooltip: 'Select this image',
                srcRest: '$restImagePath',
                srcGroup: '$groupImagePath',
                srcHover: '$hoverImagePath',
                srcDown: '$downImagePath',
                onClick: ()=>{
                    let selectedTile = viewer.tileSources[viewer.currentPage()];
                    selectedTile.isSelected=!selectedTile.isSelected;
                    if(selectedTile.isSelected){
                        //\$('#selectedFrame').val(viewer.currentPage());
                        selectImageButton.imgGroup.src='$selectedImagePath';
                        selection.toggleButton.element.style.visibility='visible';
                        resetGroupSelection(selectedTile);
                    }
                    else{
                        //\$('#selectedFrame').val(-1);
                        selectImageButton.imgGroup.src='$groupImagePath';
                        selection.disable();
                        selection.toggleButton.element.style.visibility='hidden';
                    }
                    removeOverlay(getOverlayId());
                    removeCroppedData(getOverlayId());
                    
                    removeCroppedThumb(viewer,getOverlayId());
                    
                }
            });
            
            
            viewer.scalebar({
                type: OpenSeadragon.ScalebarType.MAP,
                pixelsPerMeter: 3.356,
                minWidth: "75px",
                location: OpenSeadragon.ScalebarLocation.BOTTOM_RIGHT,
                xOffset: 5,
                yOffset: 10,
                stayInsideImage: true,
                color: "rgb(255, 255, 355,0.2)",
                fontColor: "rgb(255, 255, 255)",
                backgroundColor: "rgba(0, 0, 0)",
                fontSize: "small",
                sizeAndTextRenderer: OpenSeadragon.ScalebarSizeAndTextRenderer.KRIA_DESCRIPTION,
                barThickness: 2
            });
            viewer.addControl(selectImageButton.element, { anchor: OpenSeadragon.ControlAnchor.TOP_LEFT });   
            
            viewer.addHandler('open', () => {
                
                viewer.viewport.goHome();
                let selectedTile = viewer.tileSources[viewer.currentPage()];
                if(selectedTile.isSelected){
                    selection.toggleButton.element.style.visibility='visible';
                    selectImageButton.imgGroup.src='$selectedImagePath';
                    addOverlay(getOverlayId(), false);
                }else{
                    selection.disable();
                    selectImageButton.imgGroup.src='$groupImagePath';
                    selection.toggleButton.element.style.visibility='hidden';
                    removeOverlay(getOverlayId());
                }
                if(selectedTile.isGenerated){
                    if(!(getOverlayId() in filterValues)){
                        addFiltersForElement(getOverlayId());
                    }
                    restoreFilterValues();
                    if(typeof filters == "undefined"){
                        addFilters();
                    }
                    filters.toggleButton.element.style.visibility='visible';
                }else{
                    if(typeof filters != "undefined"){
                        filters.hideToolsPanel();
                        filters.toggleButton.element.style.visibility='hidden';
                        filters.resetFilters();
                    }
                }
                if(selectedTile.isSelectable){
                    selectImageButton.element.style.visibility='visible';
                }else{
                    selectImageButton.element.style.visibility='hidden';
                }
            });

            var selection = viewer.selection({
                allowRotation: false,
                restrictToImage: true,
                returnPixelCoordinates: false,
                onSelection: function(rect) {
                    let convertedRect=selection.viewer.viewport.viewportToImageRectangle(rect);
                    let currentTile = viewer.tileSources[viewer.currentPage()];
                    currentTile.croppedX=convertedRect.x;
                    currentTile.croppedY=convertedRect.y;
                    currentTile.croppedWidth=convertedRect.width;
                    currentTile.croppedHeight=convertedRect.height;
                    selection.toggleState();
                    removeOverlay(getOverlayId());
                    rectanglesMap[getOverlayId()]=rect;
                    addOverlay(getOverlayId(), true);
                    addCroppedTile(currentTile);
                  
                }
            });
            selection.toggleButton.addHandler('release', ()=>{
                
                if(rectanglesMap[getOverlayId()]){
                    //a roi is already selected
                    
                    $('#youAreDeletingRoi').dialog({
                        modal: true,
                        
                        width: 'auto',
                        resizable: false,
                        buttons: {
                            "Delete Crop": function () {
                                viewer.tileSources[viewer.currentPage()].croppedAreaPresent = 0;
                                viewer.tileSources[viewer.currentPage()].hasNewCroppedData = false;
                                removeCroppedData(getOverlayId());
                                removeCroppedThumb(viewer,getOverlayId());
                                $(this).dialog("close");
                            },
                            No: function () {
                                
                                selection.toggleState();
                                $(this).dialog("close");
                            }
                        }
                    });
                    $("#youAreDeletingRoi").parent().children(".ui-dialog-titlebar").children(".ui-dialog-titlebar-close").remove();
                }else{
                    viewer.tileSources[viewer.currentPage()].croppedAreaPresent = 0;
                    viewer.tileSources[viewer.currentPage()].hasNewCroppedData = false;
                    removeCroppedData(getOverlayId());
                    removeCroppedThumb(viewer,getOverlayId());
                }
               
             });
            \$(window).on('load', function() {
                viewer.tileSources.sort(function(a,b){
                    return a.parsedId - b.parsedId;
                });
                viewer.tileSources.forEach(function(currentTile) {
                    let currentOverlayId=currentTile.sectionGroup+"-"+currentTile.croppingType;
                    if(currentTile.croppedAreaPresent>0){
                        convertedRect = new OpenSeadragon.Rect(parseFloat(currentTile.croppedX),
                            parseFloat(currentTile.croppedY),
                            parseFloat(currentTile.croppedWidth),
                            parseFloat(currentTile.croppedHeight));
                        rectanglesMap[currentOverlayId] = selection.viewer.viewport.imageToViewportRectangle(convertedRect);
                        createOverlayElement(currentOverlayId);
                    }
                });
                viewer.goToPage(0);
                \$('#save-btn').click((event) => {
                    croppedImagesDataObject = [];
                    
                    var isThereAnyNewCrop=false;
                    console.log(document.getElementsByName("EventBehavior[0][validation_result]")[0].value);
                    let violationStatus= document.getElementsByName("EventBehavior[0][validation_result]")[0].value;
                    if($photoAreSelectable && violationStatus=="approved"){
                        var stopEvent=false;
                        var messageToShow="";
                        var deviceType="$deviceType";
                        switch(deviceType){
                            case "section":
                                var checkObject={"first-plate-bw" : 
                                        {   
                                            "description" : "Section start B&W shot",
                                            "selected" : false,
                                            "cropped":false
                                        },
                                        "second-plate-bw" : 
                                        {
                                            "description" : "Section end B&W shot",
                                            "selected": false,
                                            "cropped":false
                                        },
                                        "first-face" : 
                                        {   
                                            "description" : "Section start Face camera shot",
                                            "selected" : false,
                                            "cropped":false
                                        },
                                        "second-face" : 
                                        {
                                            "description" : "Section end Face camera shot",
                                            "selected": false,
                                            "cropped":false
                                        }
                                    };
                                var messagesObject={"first-plate-bw" : 
                                        {   
                                            "description" : "section start B&W shot",
                                            "type" : "plate"
                                        },
                                        "second-plate-bw" : 
                                        {
                                            "description" : "section end B&W shot",
                                            "type" : "plate"
                                        },
                                        "first-face" : 
                                        {   
                                            "description" : "section start Face camera shot",
                                            "type" : "face portion"
                                        },
                                        "second-face" : 
                                        {
                                            "description" : "section end Face camera shot",
                                            "type" : "face portion"
                                        }
                                    };
                                viewer.tileSources.forEach(
                                    function(currentTile) {
                                        var tileId= currentTile.sectionGroup+"-"+currentTile.croppingType;
                                        if(currentTile.parsedId==-1){
                                            //this is a new crop!
                                            isThereAnyNewCrop=true;
                                        }
                                        if(currentTile.isSelected){
                                            checkObject[tileId].selected=true;
                                        }
                                        if(currentTile.croppedAreaPresent>0){
                                            checkObject[tileId].cropped=true;
                                        }
                                    }
                                );
                                for(var sectionNumber in checkObject){
                                    for(var sectionAttribute in checkObject[sectionNumber]){
                                        if(!checkObject[sectionNumber][sectionAttribute]){
                                            stopEvent=true;
                                           
                                            messageToShow+="\\n <br>No "+messagesObject[sectionNumber]["type"]+" "+sectionAttribute+" in the "+messagesObject[sectionNumber]["description"]+" section.";
                                        }
                                    }
                                }
                            break;
                            default:
                            break;
                        }
                        if(stopEvent){
                            event.stopPropagation();
                            event.preventDefault();
                            \$('#modalTitle').html(messageToShow);
                            \$('#missingPicOrCropDialog').modal();
                        }else{
                            //to avoid processing the image twice, we check that the user is actually pressing "confirm" 
                            //and that there is at least one new crop to add
                            if(event.target.className!="btn" && isThereAnyNewCrop){
                                viewer.tileSources.forEach(
                                    function(currentTile, index) {
                                        if(!currentTile.isGenerated && currentTile.isSelected && currentTile.hasNewCroppedData) {
                                            var newObjToAdd = {};
                                            newObjToAdd["imageId"]=currentTile.parsedId;
                                            newObjToAdd["roi_x"]=currentTile.croppedX;
                                            newObjToAdd["roi_y"]=currentTile.croppedY;
                                            newObjToAdd["roi_width"]=currentTile.croppedWidth;
                                            newObjToAdd["roi_heigth"]=currentTile.croppedHeight;
                                            newObjToAdd["sourceIndex"]=index;
                                            newObjToAdd["overlayId"]=getOverlayId(index);
                                            croppedImagesDataObject.push(newObjToAdd);
                                        }
                                    }
                                );
                                if(croppedImagesDataObject.length>0){
                                    event.stopPropagation();
                                    event.preventDefault();
                                    addEditedImageB64(0);
                                }
                                //\$("#croppedImagesData").val(JSON.stringify(croppedImagesDataObject));
                                //\$("#roi").val(JSON.stringify(convertedRect));
                                //getEditedImageB64(viewer.tileSources.filter(isGenerated)[0].url);
                                //\$("#selectedImageId").val(viewer.tileSources[\$('#selectedFrame').val()].parsedId);
                            }
                        }
                    }
                });
            });
          
            viewer.addHandler("page", function (data) {
                              
               try {
                for(var i=0;i<$total_thumb;i++){
                   // document.getElementById("thumb-selector-"+data.eventSource.tileSources[i].parsedId).style = "border-radius:4px;width:100px;position: relative;top: 0;left: 0;";
                   
                    $("#thumb-selector-"+data.eventSource.tileSources[i].parsedId+">div>a").attr('style', "border-radius:4px;width:100px;position: relative;top: 0;left: 10px;");
                        }
                    if(data.eventSource.tileSources[data.page].parsedId != "-1"){
                        //document.getElementById("thumb-selector-"+ data.eventSource.tileSources[data.page].parsedId+">div>a>img").style = "border-radius:4px;width:100px;position: relative;top: 0;left: 0;border: 2px solid #ff9714;";
                        $("#thumb-selector-"+data.eventSource.tileSources[data.page].parsedId+">div>a").attr('style', "border-radius:4px;width:100px;position: relative;top: 0;left: 10px;border: 2px solid #ff9714;");
                        }
                    }catch(err){
                        console.log(err);
                    }
                    });
            
            function addCroppedTile(referenceTile=null){
                var canvas = document.createElement("canvas");
                var img = new Image();
                if(referenceTile == null){
                    referenceTile = viewer.tileSources[viewer.currentPage()];
                }
                img.onload = 
                    function() {
                        canvas.width = referenceTile.croppedWidth;
                        canvas.height = referenceTile.croppedHeight;
                        referenceTile.croppedAreaPresent = 1;
                        referenceTile.hasNewCroppedData = true;
                        var ctx = canvas.getContext("2d");
                        ctx.drawImage(img, 
                            referenceTile.croppedX,
                            referenceTile.croppedY,
                            referenceTile.croppedWidth,
                            referenceTile.croppedHeight,
                            0,
                            0,
                            canvas.width,
                            canvas.height);
                        img=canvas.toDataURL("image/jpeg");
                        var tileToAdd=jQuery.extend(true, {},referenceTile);
                        tileToAdd.url=img;
                        tileToAdd.isGenerated=true;
                        tileToAdd.isSelectable=false;
                        tileToAdd.isSelected=false;
                        tileToAdd.croppedAreaPresent=0;
                        tileToAdd.hasNewCroppedData=false;
                        tileToAdd.croppedX=-1;
                        tileToAdd.croppedY=-1;
                        tileToAdd.croppedWidth=-1;
                        tileToAdd.croppedHeight=-1;
                        //to identify new ones from db loaded ones, we use this field
                        tileToAdd.parsedId=-1;
                        const descriptionSubstitutionRegex = /shot.*/mg;
                        tileToAdd.description = tileToAdd.description.replace(descriptionSubstitutionRegex, "crop");
                        viewer.tileSources.push(tileToAdd);
                        delete canvas;
                        delete ctx;
                        delete img;
                        addFiltersForElement(getOverlayId());
                        viewer.goToPage(viewer.tileSources.length-1);
                        addCroppedThumb(tileToAdd,referenceTile,viewer);
                        
                    }
                img.src = viewer.world.getItemAt(0).source.url;
                
        
            }
                
            function addFiltersForElement(elementId){
                filterValues[getOverlayId()] = {
                    brightness: brightnessDefaultValue, 
                    contrast: contrastDefaultValue, 
                    gamma: gammaDefaultValue
                };
            }
                
            function restoreFilterValues(){
                //if(filterValues[getOverlayId()].brightness){
                    
                    \$("#osd-filter-brightness").val(filterValues[getOverlayId()].brightness);
                    var brightness = document.getElementById("osd-filter-brightness");
                    if(brightness){
                    \$('#osd-filter-brightness').parent().children('p').html(
                            \$('#osd-filter-brightness').parent().children('p').text().replace(/ \(.*\)/,"") +" ( " + (
                                document.getElementById("osd-filter-brightness").value || 0 ) + " )");
                            }
                    
                //}
                //if(filterValues[getOverlayId()].contrast){
                    \$("#osd-filter-contrast").val(filterValues[getOverlayId()].contrast);
                    var contrast = document.getElementById("osd-filter-contrast");
                    if(contrast){
                    \$('#osd-filter-contrast').parent().children('p').html(
                            \$('#osd-filter-contrast').parent().children('p').text().replace(/ \(.*\)/,"") +" ( " + (
                                document.getElementById("osd-filter-contrast").value || 0 ) + " )");
                            }
                //}
                //if(filterValues[getOverlayId()].gamma){
                    \$("#osd-filter-gamma").val(filterValues[getOverlayId()].gamma);
                    var gamma = document.getElementById("osd-filter-gamma");
                    if(gamma){
                    \$('#osd-filter-gamma').parent().children('p').html(
                            \$('#osd-filter-gamma').parent().children('p').text().replace(/ \(.*\)/,"") +" ( " + (
                                document.getElementById("osd-filter-gamma").value || 0 ) + " )");
                            }
                //}
            }

            function resetFilterValues(){
                filterValues[getOverlayId()] = {
                    brightness: brightnessDefaultValue, 
                    contrast: contrastDefaultValue, 
                    gamma: gammaDefaultValue
                };

            }
            function isNotGenerated(tileImage){
                return !tileImage.isGenerated;
            }
            function removeCurrentGroupGenerated(referenceTile){
                return viewer.tileSources.filter(
                    function(currentItem){
                        return (currentItem.isGenerated && 
                            (currentItem.sectionGroup != referenceTile.sectionGroup ||
                            currentItem.croppingType != referenceTile.croppingType)) ||
                                !currentItem.isGenerated;
                    }
                );
            }
            function isGenerated(tileImage){
                return tileImage.isGenerated;
            }
            function isGeneratedAndInSameGroupAs(referenceTile){
                //this should always return a one element array (based on current specifications)
                return viewer.tileSources.filter(
                    function(currentItem){
                        return currentItem.isGenerated && 
                            currentItem.sectionGroup == referenceTile.sectionGroup &&
                            currentItem.croppingType == referenceTile.croppingType;
                    }
                );
            }
            function removeCroppedData(overlayId){
                viewer.tileSources=removeCurrentGroupGenerated(viewer.tileSources[viewer.currentPage()]);
                delete filterValues[overlayId];
                removeOverlay(overlayId);
                overlaysMap[overlayId]=null;
                rectanglesMap[overlayId]=null;
                convertedRect=null;
            }

            
                
            function addEditedImageB64(elementIndex){
                var canvas = document.createElement("canvas");
                var imageToReturn;
                var img = new Image();
                img.onload = 
                    function() {
                        canvas.width = img.width;
                        canvas.height = img.height;
                        var ctx = canvas.getContext("2d");
                        ctx.drawImage(img,
                            0,
                            0);
                        //apply filters to source image
                        var imgData = ctx.getImageData(
                        0, 0, canvas.width, canvas.height);
                        var pixels = imgData.data;
                        var overlayIdToUse=croppedImagesDataObject[elementIndex].overlayId;
                        for (var i = 0; i < pixels.length; i += 4) {
                            //brightness
                            if(filterValues[overlayIdToUse].brightness != brightnessDefaultValue){
                                pixels[i] += filterValues[overlayIdToUse].brightness;
                                pixels[i + 1] += filterValues[overlayIdToUse].brightness;
                                pixels[i + 2] += filterValues[overlayIdToUse].brightness;
                            }
                            //contrast
                            if(filterValues[overlayIdToUse].contrast != contrastDefaultValue){
                                pixels[i] *= filterValues[overlayIdToUse].contrast;
                                pixels[i + 1] *= filterValues[overlayIdToUse].contrast;
                                pixels[i + 2] *= filterValues[overlayIdToUse].contrast;
                            }
                            //gamma
                            if(filterValues[overlayIdToUse].gamma != gammaDefaultValue){
                                pixels[i] = Math.pow(pixels[i] / 255, filterValues[overlayIdToUse].gamma) * 255;
                                pixels[i + 1] = Math.pow(pixels[i + 1] / 255, filterValues[overlayIdToUse].gamma) * 255;
                                pixels[i + 2] = Math.pow(pixels[i + 2] / 255, filterValues[overlayIdToUse].gamma) * 255;
                            }
                        }
                        ctx.putImageData(imgData, 0, 0);
                        //\$("#img64").val(canvas.toDataURL("image/jpeg"));
                        //impostare il return
                        croppedImagesDataObject[elementIndex]["base64"]=canvas.toDataURL("image/jpeg");
                        delete canvas;
                        delete ctx;
                        
                        elementIndex++;
                        if(elementIndex < croppedImagesDataObject.length){
                           addEditedImageB64(elementIndex);
                        }else{
                           //time to submit baby
                           \$("#croppedImagesData").val(JSON.stringify(croppedImagesDataObject));
                           \$("#event-form").submit();
                        }
                    }
                img.src = isGeneratedAndInSameGroupAs(viewer.tileSources[croppedImagesDataObject[elementIndex].sourceIndex])[0].url;
            }

            function addOverlay(overlayId,createElement=false){
                if(createElement){
                    createOverlayElement(overlayId);
                }
                viewer.addOverlay({
                    element: overlaysMap[overlayId],
                    location: rectanglesMap[overlayId]
                });
            }
            function createOverlayElement(overlayId){
                if(overlayId in overlaysMap){
                    delete overlaysMap[overlayId];
                }
                overlaysMap[overlayId] = document.createElement('div');
                overlaysMap[overlayId].id = overlayId;
                overlaysMap[overlayId].className = 'highlight';
            }
            function addFilters(){
                
                filters = 
                    viewer.imagefilters(
                            {   
                                toolsWidth: 180,
                                toolsHeight: 200,
                                toolsTop: 35
                            }
                    );
                viewer.goToPage(viewer.currentPage());
            }
                
            function getOverlayId(selectedPage=-1){
                if(selectedPage<0){
                    selectedPage = viewer.currentPage();
                }
                let selectedTile = viewer.tileSources[selectedPage];
                return selectedTile.sectionGroup+"-"+selectedTile.croppingType;
            }
                
            function removeOverlay(overlayId){
                if(overlaysMap[overlayId]!==undefined){
                    viewer.removeOverlay(overlayId);
                }
            }
                
            function resetGroupSelection(tileToMatch){
                viewer.tileSources.forEach(
                    function(currentTile) {
                        if(currentTile.url !== tileToMatch.url){
                            //excluse self-match
                            if(currentTile.sectionGroup == tileToMatch.sectionGroup &&
                                currentTile.croppingType == tileToMatch.croppingType){
                                    currentTile.isSelected = false;
                                    currentTile.croppedAreaPresent = 0;
                                    currentTile.hasNewCroppedData = false;
                                    currentTile.croppedX = -1;
                                    currentTile.croppedY = -1;
                                    currentTile.croppedWidth = -1;
                                    currentTile.croppedHeight = -1;
                            }
                        }
                    }
                );
            }
                
            function getDesiredAspectRatio(croppingType){
                var deviceType="$deviceType";
                var aspectRatio=0;
                switch(deviceType){
                  case "section":
                    switch(croppingType){
                        case "face":
                            aspectRatio=(3.0)/(4.0);
                        break;
                        case "plate-bw":
                            aspectRatio=(9.0)/(16.0);
                        break;
                        default:
                            aspectRatio=0;
                        break;
                    }
                  break;
                }
                return aspectRatio;
            }
      
        </script>  
            
EOT;

        $script->writeline($scriptToWrite);

        echo ($script);
        //file_put_contents("C:/Users/n.gasbarro/Desktop/OpenSeaDragon/index2.html",$script->buffer);

        return $id;
    }

}
