<?php
/**
* EfrontLesson Class file
*
* @package eFront
* @version 3.5.0
*/

/**
 * EfrontLessonException class
 *
 * This class extends Exception class and is used to issue errors regarding lessons
 * @author Venakis Periklis <pvenakis@efront.gr>
 * @version 1.0
 */
class EfrontLessonException extends Exception
{
    const NO_ERROR          = 0;
    const LESSON_NOT_EXISTS = 201;
    const INVALID_ID        = 202;
    const CANNOT_CREATE_DIR = 203;
    const INVALID_LOGIN     = 204;
    const DATABASE_ERROR    = 205;
    const DIR_NOT_EXISTS    = 206;
    const FILESYSTEM_ERROR  = 207;
    const DIRECTION_NOT_EXISTS = 208;
    const GENERAL_ERROR     = 299;
}

/**
 * EfrontLesson class
 *
 * This class represents a lesson
 * @author Venakis Periklis <pvenakis@efront.gr>
 * @version 1.0
 */
class EfrontLesson
{
    /**
     * The lesson array.
     *
     * @since 3.5.0
     * @var array
     * @access public
     */
    public $lesson = array();

    /**
     * The lesson users. Calling getUsers() initializes it; otherwise, it evaluates to false.
     *
     * @since 3.5.0
     * @var array
     * @access protected
     */
    protected $users = false;

    /**
     * The lesson conditions. Calling getConditions() initializes it; otherwise, it evaluates to false.
     *
     * @since 3.5.0
     * @var array
     * @access protected
     * @see getConditions()
     */
    protected $conditions = false;

    /**
     * The lesson directory, equals G_LESSONSPATH.$lessonId
     *
     * @since 3.5.0
     * @var string
     * @access protected
     */
    protected $directory = '';


    /**
     * Default lesson options
     *
     * @since 3.5.0
     * @var string
     * @access protected
     */
    public $options = array('theory'          => 1,
                            'examples'        => 1,
                            'projects'        => 1,
                            'tests'           => 1,
                            'survey'          => 1,
                            'rules'           => 1,
                            'forum'           => 1,
                            'comments'        => 1,
                            'online'          => 1,
                            'chat'            => 1,
                            'scorm'           => 1,
                            'dynamic_periods' => 0,
                            'digital_library' => 1,
                            'calendar'        => 1,
                            'new_content'     => 1,
                            'glossary'        => 1,
                            'tracking'        => 1,
                            'auto_complete'   => 0,
                            'content_tree'    => 1,
                            'default_positions' => '');

    /**
     * Class constructor
     *
     * This function is used to instantiate the class. The instatiation is done
     * based on a lesson id or a lesson array.
     * <br/>Example:
     * <code>
     * $lesson = new EfrontLesson(32);                     //32 is a lesson id
     * $result = eF_getTableData("lessons", "*", "id=32"); //Get lesson data from databasse
     * $lesson = new EfrontLesson($result[0]);             //Instantiate using prepared data
     * </code>
     *
     * @param int $lesson Either the lesson id or the lesson data
     * @since 3.5.0
     * @access public
     */
    function __construct($lesson) {
        if (!is_array($lesson)) {
            if (!eF_checkParameter($lesson, 'id')) {
                throw new EfrontLessonException(_INVALIDID.": $lesson", EfrontLessonException :: INVALID_ID);
            }
            $result = eF_getTableData("lessons", "*", "id = $lesson");

            if (sizeof($result) == 0) {
                throw new EfrontLessonException(_LESSONDOESNOTEXIST.": $lesson", EfrontLessonException :: LESSON_NOT_EXISTS);
            }
            $this -> lesson = $result[0];
        } else {
            $this -> lesson = $lesson;
        }

        if (!is_dir(G_LESSONSPATH.$this -> lesson['id'])) {
            mkdir(G_LESSONSPATH.$this -> lesson['id']);
        }
        $this -> directory = G_LESSONSPATH.$this -> lesson['id'].'/';
        //echo "!".$this -> directory."@";
        if ($this -> lesson['options'] && $options = unserialize($this -> lesson['options'])) {
            $newOptions      = array_diff_key($this -> options, $options);    //$newOptions are lesson options that were added to the EfrontLesson object AFTER the lesson options serialization took place
            $this -> options = $options + $newOptions;                        //Set lesson options
        }

    }

    /**
     * Create lesson
     *
     * This function created a new lesson. This involves creating
     * the database instance, creating the corresponding filesystem
     * folder (read below) and finally creating corresponding forum and chat entries
     * as well as any other information needed.
     * The function argument is an array with field values, corresponding to database
     * fields. All fields are optional, and if absent they are filled with default values,
     * but 'name', 'languages_NAME' and 'directions_ID' are strongly recommended to be defined
     * <br/>Example:
     * <code>
     * $fields = array('name' => 'Test lesson', 'directions_ID' => 2, 'languages_NAME' => 'english');
     * try {
     *   $newLesson = EfrontLesson :: createLesson($fields);                     //$newLesson is now a new lesson object
     * } catch (Exception $e) {
     *   echo $e -> getMessage();
     * }
     * </code><br/>
     * When a lesson is created, a folder named after the lesson id is created
     * inside the G_LESSONSPATH folder. For example, if G_LESSONSPATH is
     * /var/www/efront/www/content/lessons/ and the new lesson gets the id 35,
     * a corresponding folder will be created: /var/www/efront/www/content/lessons/35/
     *
     * @param array $fields The new lesson characteristics
     * @return EfrontLesson the new lesson object
     * @since 3.5.0
     * @access public
     * @static
     */
    public static function createLesson($fields) {
        //These are the mandatory fields. In case one of these is absent, fill it in with a default value
        !isset($fields['name'])           ? $fields['name']           = 'Default name'                                : null;
        !isset($fields['languages_NAME']) ? $fields['languages_NAME'] = $GLOBALS['configuration']['default_language'] : null;
        if (!isset($fields['directions_ID'])) {
            $directions = eF_getTableData("directions", "id");
            sizeof($directions) > 0 ? $fields['directions_ID'] = $directions[0]['id'] : $fields['directions_ID'] = 1;
        }

        $languages      = EfrontSystem :: getLanguages(true);
        $lessonMetadata = array('title'       => $fields['name'],
                                'creator'     => $GLOBALS['currentUser'] -> user['name'].' '.$GLOBALS['currentUser'] -> user['surname'],
                                'publisher'   => $GLOBALS['currentUser'] -> user['name'].' '.$GLOBALS['currentUser'] -> user['surname'],
                                'contributor' => $GLOBALS['currentUser'] -> user['name'].' '.$GLOBALS['currentUser'] -> user['surname'],
                                'date'        => date("Y/m/d", time()),
                                'language'    => $languages[$fields['languages_NAME']]);
        $fields['metadata'] = serialize($lessonMetadata);

        $lessonId = eF_insertTableData("lessons", $fields);                                    //Insert the lesson to the database

        ///MODULES1 - Module lesson add events
        // Get all modules (NOT only the ones that have to do with the user type)
        $modules = eF_loadAllModules();
        // Trigger all necessary events. If the function has not been re-defined in the derived module class, nothing will happen
        foreach ($modules as $module) {
            $module -> onNewLesson($lessonId);
        }

        //If a folder with the name $lessonId already exists, delete the lessons entry and retry, so that a new id will be used
        while (is_dir(G_LESSONSPATH.$lessonId) && $q++ < 10000) {                              //$q is put here to prevent infinite loops
            $newLessonId = eF_insertTableData("lessons", $fields);                            //"Issue" the new id by inserting a new database entry
            eF_deleteTableData("lessons", "id=$lessonId");                                     //delete the previous entry
            $lessonId     = $newLessonId;
        }
        if ($q == 10000) {
            return false;
        }

        EfrontSearch :: insertText($fields['name'], $lessonId, "lessons", "title");

        if (!mkdir(G_LESSONSPATH.$lessonId, 0755)) {
            eF_deleteTableData("lessons", "id=$lessonId");                                 //If the folder could not be created, delete the stored lesson database entry and then propagate the exception
            throw new EfrontLessonException(_LESSONDIRECTORYCANNOTBCREATED, EfrontLessonException :: CANNOT_CREATE_DIR);
        }

        //Create corresponding forum and chat entries for the new lesson
        $forumFields = array('title'       => $fields['name'],
                             'lessons_ID'  => $lessonId,
                             'parent_id'   => 0,
                             'status'      => 'public',
                             'users_LOGIN' => $_SESSION['s_login'],
                             'comments'    => '');
        $forum_id = eF_insertTableData("f_forums", $forumFields);

        EfrontSearch :: insertText($fields['name'], $forum_id, "f_forums", "title");

        $chatFields = array('name'             => $fields['name'],
                            'create_timestamp' => time(),
                            'type'             => 'public',
                            'users_LOGIN'      => $_SESSION['s_login'],
                            'lessons_ID'       => $lessonId,
                            'active'           => 1);
        eF_insertTableData("chatrooms", $chatFields);

        $newLesson = new EfrontLesson($lessonId);

        return $newLesson;
    }

    /**
     * Delete lesson
     *
     * This function is used to delete an existing lesson. In order to do
     * this, it caclulates all the lesson dependendant elements, deletes them
     * and finally deletes the lesson itself.
     *
     * <br/>Example:
     * <code>
     * try {
     *   $lesson = new EfrontLesson(32);                     //32 is the lesson id
     *   $lesson -> delete();
     * } catch (Exception $e) {
     *   echo $e -> getMessage();
     * }
     * </code>
     *
     * @return boolean True if everything is ok
     * @since 3.5.0
     * @access public
     */
    public function delete() {
        $result = eF_getTableDataFlat("content", "id", "lessons_ID=".$this -> lesson['id']);
        $list   = implode(",", $result['id']);

        $id = $this -> lesson['id'];

        ///MODULES2 - Module lesson delete events - Before anything else
        // Get all modules (NOT only the ones that have to do with the user type)
        $modules = eF_loadAllModules();
        // Trigger all necessary events. If the function has not been re-defined in the derived module class, nothing will happen
        foreach ($modules as $module) {
            $module -> onDeleteLesson($id);
        }

        eF_deleteTableData("lessons", "id=$id");
        eF_deleteTableData("content", "lessons_ID=$id");
        eF_deleteTableData("news", "lessons_ID=$id");
        eF_deleteTableData("periods", "lessons_ID=$id");
        eF_deleteTableData("users_to_lessons", "lessons_ID=$id");
        EfrontSearch :: removeText('lessons', $id, '');

        //delete the forums of this lesson
        $lessons_forums    = eF_getTableData("f_forums", "id","lessons_ID=$id");
        foreach($lessons_forums as $value) {
            $result_forums = eF_getTableData("f_forums", "*");
            $forum_tree    = array();
            //Convert array to tree. At the end of the loop, the $forums array will hold the forum tree, where each node is an array of its child nodes
            while (sizeof($result_forums) > 0 && $count++ < 10000) {            //$count is put here to prevent infinite loops
                $node                     = current($result_forums);            //Get the key/node pairs of the first array element
                $key                      = key($result_forums);
                $parent_id                = $node['parent_id'];
                $forum_tree[$parent_id][] = $node['id'];                        //Append to the tree array, at the forum id index, the id of its child
                $forum_tree[$node['id']]  = array();
                $forums[$node['id']]      = $node;                              //Copy node to forums, which will be used later as forums source
                unset($result_forums[$key]);                                    //We visited the node, so delete it from the (array) graph
            }

            $children = $forum_tree[$value[id]];                                //Get all the forum's direct siblings
            for ($i = 0; isset($children[$i]); $i++) {                          //Find all the forum siblings' siblings
                $children = array_merge ($children, $forum_tree[$children[$i]]);
            }
            $children[] = $value[id];                                            //Append the deleted forum to the childrens list

            $topics     = eF_getTableDataFlat("f_topics", "id", "f_forums_ID in (".implode(",", $children).")");    //Get forums' topics
            if (sizeof($topics) > 0) {                                                                              //Delete forums' messages and topics
                $fmid = eF_getTableDataFlat("f_messages", "id", "f_topics_ID in (".implode(",", $topics['id']).")");
                EfrontSearch :: removeText('f_messages', implode(",", $fmid['id']), '', true);
                eF_deleteTableData("f_messages", "topics_id in (".implode(",", $topics['id']).")");
                eF_deleteTableData("f_topics", "id in (".implode(",", $topics['id']).")");
            }
            $fpid = eF_getTableDataFlat("f_poll", "id", "f_forums_ID in (".implode(",", $children).")");
            if (sizeof($fmid) > 0) {
                EfrontSearch :: removeText('f_poll', implode(",", $fmid['id']), '', true);
            }
            if (sizeof($children) > 0) {
                eF_deleteTableData("f_poll", "f_forums_ID in (".implode(",", $children).")");                           //Delete polls
                EfrontSearch :: removeText('f_forums', implode(",", $children), '', true);
                eF_deleteTableData("f_forums", "id in (".implode(",", $children).")");                                  //Finally, delete forums themselves
            }
        }

        if ($list) {
            eF_deleteTableData("scorm_data", "content_ID IN ($list)");
            eF_deleteTableData("comments", "content_ID IN ($list)");
            eF_deleteTableData("questions", "content_ID IN ($list)");
            eF_deleteTableData("rules", "content_ID IN ($list)");
            eF_deleteTableData("rules", "rule_content_ID IN ($list)");
            eF_deleteTableData("logs", "comments IN ($list)");
            EfrontSearch :: removeText('content', $list, '', true);
            //$list_as_text = "'".str_replace(", ", "', '", $list)."'";
            //eF_deleteTableData("logs", "comments IN ($list_as_text)");

            $result     = eF_getTableDataFlat("tests", "id", "content_ID IN ($list)");
            $tests_list = implode(",", $result['id']);
            eF_deleteTableData("tests", "content_ID IN ($list)");

            if ($tests_list) {
                eF_deleteTableData("tests_to_questions", "tests_ID IN ($tests_list)");
                $result          = eF_getTableDataFlat("done_tests", "id", "tests_ID IN ($tests_list)");
                $done_tests_list = implode(",", $result['id']);
                //$list_as_text    = "'".str_replace(", ", "', '", $list)."'";
                //eF_deleteTableData("logs", "action='tests' AND comments IN ($list_as_text)");
                eF_deleteTableData("logs", "action='tests' AND comments IN ($list)");

                if ($done_tests_list) {
                    eF_deleteTableData("done_tests", "id IN ($done_tests_list)");
                    eF_deleteTableData("done_questions", "done_tests_ID IN ($done_tests_list)");
                }
            }
        }

        $chatroom = eF_getTableData("chatrooms", "id", "lessons_ID=".$this -> lesson['id']);                                          //Get the lesson chat room
        if (sizeof($chatroom) > 0) {
            eF_deleteTableData("chatmessages", "chatrooms_ID=".$chatroom[0]['id']);                                 //Delete the chat room messages
            eF_deleteTableData("chatrooms", "id=".$chatroom[0]['id']);                                              //Delete the lesson chatroom
        }

        $courses = eF_getTableData("courses");
        for ($i = 0; $i < sizeof($courses); $i++) {
            $course_lessons = unserialize($courses[$i]['lessons']);
            if (($key = array_search($this -> lesson['id'], $course_lessons)) !== false) {
                $course_rules = unserialize($courses[$i]['rules']);
                unset($course_rules[$this -> lesson['id']]);
                unset($course_lessons[$key]);
                $course_rules   ? $course_rules   = serialize($course_rules)   : $course_rules   = '';
                $course_lessons ? $course_lessons = serialize($course_lessons) : $course_lessons = '';
                eF_updateTableData("courses", array("lessons" => $course_lessons, "rules" => $course_rules), "id=".$courses[$i]['id']);
            }
        }

        try {
            $directory = new EfrontDirectory($this -> directory);
            $directory -> delete();
        } catch (EfrontFileException $e) {
        }

        return true;
    }


    /**
     * Returns the direction of the lesson
     *
     * This function is used to return the direction of the lesson
     * <br/>Example:
     * <code>
     * $direction_info = $lesson -> getDirection();
     * </code>
     *
     * @return array The returned array has two fields: id and name of the lesson's direction
     * @since 3.5.0
     * @access public
     */
    public function getDirection(){
        $result         = array();
        $res            = eF_getTableData("directions", "name", "id=".$this -> lesson['directions_ID']);
        $direction_name = $res[0]['name'];
        $result['id']   = $this -> lesson['directions_ID'];
        $result['name'] = $direction_name;
        return $result;
    }

    /**
     * Check if a lesson with a specified lesson_id exists
     *
     * This function is used to check if a lesson with a specified id exists
     * <br/>Example:
     * <code>
     * $flg -> EfrontLesson :: exists(2);
     * </code>
     *
     * @param  int  The lesson id to check
     * @return boolean True if the lesson exists
     * @since 3.5.0
     * @access public
     */
    public static function exists($lessonId){
        $res = ef_getTableData("lessons","id","id=".$lessonId);
        if (sizeof($res) > 0){
            return true;
        }
        else{
            return false;
        }
    }

    /**
     * Activate lesson
     *
     * This function is used to activate a lesson
     * <br/>Example:
     * <code>
     * $lesson -> activate();
     * </code>
     *
     * @return boolean True if everything is ok
     * @since 3.5.0
     * @access public
     */
    public function activate() {
        $this -> lesson['active'] = 1;
        $this -> persist();
        return true;
    }

    /**
     * Deactivate lesson
     *
     * This function is used to deactivate a lesson
     * <br/>Example:
     * <code>
     * $lesson -> deactivate();
     * </code>
     *
     * @return boolean True if everything is ok
     * @since 3.5.0
     * @access public
     */
    public function deactivate() {
        $this -> lesson['active'] = 0;
        $this -> persist();
        return true;
    }

    /**
     * Delete lesson (statically)
     *
     * This function is used to delete an existing lesson. In order to do
     * this, it caclulates all the lesson dependendant elements, deletes them
     * and finally deletes the lesson itself. This function is the same as
     * EfrontLesson :: delete(), except that it is called statically, so it
     * instatiates first the lesson objects and then calls delete() on it.
     * Alternatively, $lesson may be already a lesson object.
     * <br/>Example:
     * <code>
     * try {
     *   EfrontLesson :: delete(32);                     //32 is the lesson id
     * } catch (Exception $e) {
     *   echo $e -> getMessage();
     * }
     * </code>
     *
     * @param mixed $lesson The lesson id or a lesson object
     * @return boolean True if everything is ok
     * @since 3.5.0
     * @access public
     * @static
     */
    public static function deleteLesson($lesson) {
        if (!($lesson instanceof EfrontLesson)) {
            $lesson = new EfrontLesson($lesson);
        }
        return $lesson -> delete();
    }

    /**
     * Get lesson directory
     *
     * This function returns the lesson directory, normally G_LESSONSPATH.$lesson['id']
     * <br/>Example:
     * <code>
     * $lesson = new EfrontLesson(43);          //Instantiate object for lesson with id 43
     * $lesson -> getDirectory();               //Returns something like /var/sites/efront/www/content/lessons/43
     * $lesson -> getDirectory(true);           //Returns EfrontDirectory object for lesson directory
     * </code>
     *
     * @param boolean $returnObject If true, an EfrontDirectory object is returned
     * @return mixed Either a string with the lesson directory, or the equivalent EfrontDirectory object
     * @since 3.5.0
     * @access public
     * @todo create if not exists
     */
    public function getDirectory($returnObject = false) {
        if ($returnObject) {
            return new EfrontDirectory($this -> directory);
        } else {
            return $this -> directory;
        }
    }

    /**
     * Get lesson users
     *
     * This function returns an array with the lesson users.
     * <br/>Example:
     * <code>
     * $lesson = new EfrontLesson(32);                      //32 is a lesson id
     * $lessonUsers    = $lesson -> getUsers();             //Get the lesson users
     * $nonLessonUsers = $lesson -> getNonUsers();          //Get the users that don't have the lesson, but are eligible to
     * </code>
     * The returned array keys match the users logins
     *
     * @param string $basicType The user's basic type in the lesson
     * @param boolean $refresh Whether to explicitly refresh the object cached data set
     * @return array A 2-dimensional array with lesson users per type, or a 1-dimensional array with lesson users of the specified type
     * @since 3.5.0
     * @access public
     */
    public function getUsers($basicType = false, $refresh = false) {
        if ($this -> users === false || $refresh) {                //Make a database query only if the variable is not initialized, or it is explicitly asked
            $this -> users = array();
            $result = eF_getTableData("users, users_to_lessons", "users.*, users_to_lessons.user_type as role", "users_LOGIN = login and lessons_ID=".$this -> lesson['id']);

            foreach ($result as $value) {
                $this -> users[$value['login']] = array('login'           => $value['login'],
                                                        'email'           => $value['email'],
                                                        'name'            => $value['name'],
                                                        'surname'         => $value['surname'],
                                                        'basic_user_type' => $value['user_type'],
                                                        'user_types_ID'   => $value['user_types_ID'],
                										'role'            => $value['role'],
                                                        'active'          => $value['active'],
                                                        'partof'          => 1);
            }
        }

        if ($basicType) {
            $users = array();
            $roles = EfrontLessonUser :: getLessonsRoles();
            foreach ($this -> users as $login => $value) {
                if ($roles[$value['role']] == $basicType) {
                    $users[$login] = $value;
                }
            }

            return $users;
        } else {
            return $this -> users;
        }

    }

    /**
     * Get users that don't have the lesson
     *
     * This function is complementary to getUsers(); it returns only those users
     * that don't have this lesson.
     * <br/>Example:
     * <code>
     * $lesson = new EfrontLesson(32);                      //32 is a lesson id
     * $lessonUsers    = $lesson -> getUsers();             //Get the lesson users
     * $nonLessonUsers = $lesson -> getNonUsers();          //Get the users that don't have the lesson, but are eligible to
     * </code>
     * The returned array keys match the users logins
     *
     * @param boolean $type The users type
     * @return array A list with eleigible users for this lesson
     * @since 3.5.0
     * @access public
     */
    public function getNonUsers($type = false) {
        foreach ($this -> getUsers() as $key => $value) {
            $lessonUsers[$value['login']] = $value;
        }

        $sql = "users.active = 1 and users.languages_NAME = '".$this -> lesson['languages_NAME']."' and login NOT IN ('".implode("','", array_keys($lessonUsers))."') ";
        $type && in_array($type, EfrontUser :: basicUserTypes) ? $sql.= "and user_type == '".$type."'" : $sql.= "and user_type != 'administrator'";

        $result = eF_getTableData("users", "*", $sql);
        $nonLessonUsers = array();
        foreach ($result as $value) {
            $nonLessonUsers[$value['login']] = array('login'           => $value['login'],
                                                     'email'           => $value['email'],
                                                     'name'            => $value['name'],
                                                     'surname'         => $value['surname'],
                                                     'basic_user_type' => $value['user_type'],
                                                     'user_types_ID'   => $value['user_types_ID'],
            										 'role'            => $value['user_types_ID'] ? $value['user_types_ID'] : $value['user_type'],
                                                     'active'          => $value['active'],
                                                     'partof'          => 0);
        }

        return $nonLessonUsers;
    }

    /**
     * Get lesson course
     *
     * This function returns the courses that this lesson is part
     * of.
     * <br/>Example:
     * <code>
     * $courses = $this -> getCourses();                    //Return an array of course ids and properties
     * $courses = $this -> getCourses(true);                //Return an array of EfrontCourse objects
     * </code>
     *
     * @param boolean $returnObjects Whether to return EfrontCourse objects or a simple arrays
     * @return array The courses list, where keys are ids and values are either arrays or EfrontCourse objects
     * @since 3.5.0
     * @access public
     */
    public function getCourses($returnObjects = false) {
        $result  = eF_getTableData("courses, lessons_to_courses", "courses.*", "lessons_ID = ".$this -> lesson['id']);
        $courses = array();
        foreach ($result as $value) {
            $returnObjects ? $courses[$value['id']] = new EfrontCourse($value['id']) : $courses[$value['id']] = $value;
        }

        return $courses;
    }

    /**
     * Add users to lesson
     *
     * This function is used to register one or more users to the current lesson. A single login
     * or an array of logins may be specified
     * <br/>Example:
     * <code>
     * $lesson -> addUsers('joe', 'professor');         //Add the user with login 'joe' as a professor to this lesson
     * $users = array('joe', 'mary', 'mike');
     * $types = array('student', 'student', 'professor');
     * $lesson -> addUsers($users, $types);             //Add the users in the array $users with roles $types
     * </code>
     *
     * @param mixed $login The user login name
     * @param mixed $role The user role for this lesson, defaults to 'student'
     * @return boolean true if everything is ok
     * @since 3.5.0
     * @access public
     */
    public function addUsers($login, $role = 'student') {
        if (!is_array($login)) {
            $login = array($login);
            $role  = array($role);
        }

        $userTypes = eF_getTableDataFlat("user_types", "id, basic_user_type");
        $userTypes = array_combine($userTypes['id'], $userTypes['basic_user_type']);

        $lessonUsers = $this -> getUsers();
        $addedUsers  = array();
        foreach ($login as $key => $value) {
            if (!in_array($value, array_keys($lessonUsers))) {
                if (eF_checkParameter($value, 'login')) {
                    $fields = array('users_LOGIN'    => $value,
                                	'lessons_ID'     => $this -> lesson['id'],
                                	'active'         => 1,
                                	'from_timestamp' => time(),
                                	'user_type'      => current($role));
                    next($role);
                    if (!eF_insertTableData("users_to_lessons", $fields)) {
                        $errors[] = _CANNOTADDUSERTOLESSON.' ('.EfrontLessonException :: DATABASE_ERROR.')';
                    } else {
                        if ($fields['user_type'] == 'student' || $userTypes[$fields['user_type']]['basic_user_type'] == 'student') {
                            $addedStudents[] = $value;
                        }
                    }
                } else {
                    $errors[] = _INVALIDLOGIN.': '.$value.' ('.EfrontLessonException :: INVALID_LOGIN.')';
                }
            }
        }

        //Assign new users to auto projects
        $lessonProjects     = $this -> getProjects();
        $autoAssignProjects = array();
        foreach ($lessonProjects as $id => $project) {
            if ($project['auto_assign']) {
                $autoAssignProjects[$id] = new EfrontProject($id);
            }
        }
        if (sizeof($addedUsers) > 0 && sizeof($addedStudents) > 0) {
            foreach ($autoAssignProjects as $project) {
                $project -> addUsers($addedStudents);
            }
        }

        if (!isset($errors)) {
            return true;
        } else {
            throw new EfrontLessonException(_PROBLEMADDINGUSERSTOLESSON.': '.implode("<br>", $errors), EfrontLessonException :: GENERAL_ERROR);
        }
    }

    /**
     * Remove user from lesson
     *
     * This function is used to remove a user from the current lesson. A single login
     * or an array of logins may be specified
     * <br/>Example:
     * <code>
     * $lesson -> removeUsers('jdoe');          //Remove the user with login 'jdoe'
     * </code>
     *
     * @param string $login The user login name
     * @return boolean true if everything is ok
     * @since 3.5.0
     * @access public
     * @todo remove him from projects list
     */
    public function removeUsers($login) {
        if (!is_array($login)) {
            $login = array($login);
        }
        foreach ($login as $value) {
            if (eF_checkParameter($value, 'login')) {
                eF_deleteTableData("users_to_lessons", "users_LOGIN='$value' and lessons_ID=".$this -> lesson['id']);
            }
        }
        if (!isset($errors)) {
            return true;
        } else {
            throw new EfrontLessonException(_PROBLEMADDINGUSERSTOLESSON.': '.implode("<br>", $errors), EfrontLessonException :: GENERAL_ERROR);
        }
    }

    /**
     * Set user roles in lesson
     *
     * This function sets the role for the specified user
     * <br/>Example:
     * <code>
     * $lesson -> addUsers('jdoe', 'student');              //Added the user 'jdoe' in the lesson, having the role 'student'
     * $lesson -> setRoles('jdoe', 'professor');                //Updated jdoe's role to be 'professor'
     * </code>
     * Multiple values can be set if arguments are arrays
     *
     * @param mixed $login The user login name
     * @param mixed $role The user role for this lesson
     * @return boolean true if everything is ok
     * @since 3.5.0
     * @access public
     */
    public function setRoles($login, $role) {
        if (!is_array($login)) {
            $login = array($login);
            $role  = array($role);
        }
        foreach ($login as $key => $value) {
            if (eF_checkParameter($value, 'login')) {
                if (!eF_updateTableData("users_to_lessons", array('user_type' => $role[$key]), "users_LOGIN='".$value."' and lessons_ID=".$this -> lesson['id'])) {
                    $errors[] = _CANNOTUPDATEUSERLESSONINFORMATION.' ('.EfrontLessonException :: DATABASE_ERROR.')';
                }
            } else {
                $errors[] = _INVALIDLOGIN.': '.$value.' ('.EfrontLessonException :: INVALID_LOGIN.')';
            }
        }
        if (!isset($errors)) {
            return true;
        } else {
            throw new EfrontLessonException(_PROBLEMUPDATINGUSERSTOLESSON.': '.implode("<br>", $errors), EfrontLessonException :: GENERAL_ERROR);
        }
    }

    /**
     * Get the user role in this lesson
     * 
     * This function gets the role of the specified user in the specified lesson
     * <br>Example:
     * <code>
     * $lesson -> getRole('jdoe');		//Return the user's role, e.g. 'professor', or, if it's a custom role, it's id, e.g. '5' 
     * </code>
     *
     * @param string $login The user's login
     * @return mixed The user's role in lesson
     * @since 3.5.0
     * @access public
     */
    public function getRole($login) {
        $lessonUsers = $this -> getUsers();
        if (in_array($login, array_keys($lessonUsers))) {
            return $lessonUsers[$login]['role'];
        } else {
            throw new EfrontUserException(_USERDOESNOTHAVETHISLESSON.": ".$lesson, EfrontUserException :: USER_NOT_HAVE_LESSON);
        }
    }

    /**
     * Get the tests of the lesson
     *
     * This returns the tests of the lesson
     * <br/>Example:
     * <code>
     * $lesson = new EfrontLesson(12);
     * $tests = $lesson -> getTests(true);
     *
     * @param bool returnObjects. Flag to indicate whether to return a list of objects or a list of ids
     * @return array the lesson's tests (either an array of ids or an array of EfrontTest objects)
     * @since 3.5.0
     * @access public
     * @static
     */
    public function getTests($returnObjects = false){
        $tests = array();
        $test_data = ef_getTableData("tests t, content c", "t.*", "t.content_id = c.id and c.lessons_ID=".$this -> lesson['id']);
        foreach ($test_data as $t){
            if (!$returnObjects){
                $tests[] = $t['id'];
            }
            else{
                $test = new EfrontTest($t['id']);
                $tests[$t['id']] = $test;
            }
        }
        return $tests;
    }

    /**
     * Get the scorm tests of the lesson
     *
     * This returns the tests of the lesson
     * <br/>Example:
     * <code>
     * $lesson = new EfrontLesson(12);
     * $tests = $lesson -> getScormTests();
     *
     *
     * @return array the lesson's scorm tests (an array of ids)
     * @since 3.5.0
     * @access public
     * @static
     */
    public function getScormTests(){
        $tests = array();
        $scorm_data = ef_getTableData("content", "id", "lessons_ID=".$this -> lesson['id']." and ctg_type='scorm_test'");
        foreach ($scorm_data as $data){
            $tests[] = $data['id'];
        }
        return $tests;
    }



    /**
    * Get the questions of the lesson
    *
    * This returns the questions of the lesson
    * <br/>Example:
    * <code>
    * $lesson = new EfrontLesson(12);
    * $questions = $lesson -> getQuestions(true);
    *
    * @param bool returnObjects. Flag to indicate whether to return a list of objects or a list of ids
    * @return array the lesson's questions (either an array of ids or an array of Question objects)
    * @since 3.5.0
    * @access public
    * @static
    */
    public function getQuestions($returnObjects = true){
        $questions = array();
        $question_data = ef_getTableData("questions q, tests_to_questions tq, content c, tests t", "distinct (q.id)", "tq.questions_ID = q.id and tq.tests_ID = t.id and t.content_id = c.id and c.lessons_ID=".$this -> lesson['id']);
        foreach ($question_data as $qid){
            if (!$returnObjects){
                $questions[] = $qid['id'];
            }
            else{
                $question = QuestionFactory :: factory($qid['id']);
                $questions[$qid['id']] = $question;
            }
        }
        return $questions;
    }



    /**
     * Get lesson information
     *
     * This function returns the lesson information in an array
     * with attributes: 'general_description', 'assessment',
     * 'objectives', 'lesson_topics', 'resources', 'other_info',
     * as well as other information, including professors, projects
     * etc.
     * If a user is specified, the information is customized on this
     * user.
     *
     * <br/>Example:
     * <code>
     * $info = $lesson -> getInformation();         //Get lesson information
     * $info = $lesson -> getInformation('jdoe');   //Get lesson information, customizable for user 'jdoe'
     * </code>
     *
     * @param string $user The user login to customize lesson information for
     * @return array The lesson information
     * @since 3.5.0
     * @access public
     */
    public function getInformation($user = false, $information = false) {

        $lessonContent = new EFrontContentTree($this -> lesson['id']);

        $testIds = array();
        foreach (new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($lessonContent -> tree), RecursiveIteratorIterator :: SELF_FIRST), array('active' => 1, 'ctg_type' => 'tests')) as $key => $value) {
            $testIds[$key] = $key;            //Count tests
        }
        foreach (new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($lessonContent -> tree), RecursiveIteratorIterator :: SELF_FIRST), array('active' => 1, 'ctg_type' => 'scorm_test')) as $key => $value) {
            $testIds[$key] = $key;            //Count tests
        }

        $theoryIds = array();
        foreach (new EfrontVisitableFilterIterator(new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($lessonContent -> tree), RecursiveIteratorIterator :: SELF_FIRST), array('ctg_type' => 'theory'))) as $key => $value) {
            $theoryIds[$key] = $key;            //Count theory
        }
//        foreach (new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($lessonContent -> tree), RecursiveIteratorIterator :: SELF_FIRST), array('ctg_type' => 'scorm', 'active' => 1)) as $key => $value) {
//            $theoryIds[$key] = $key;            //Count theory
//        }

        $exampleIds = array();
        foreach (new EfrontVisitableFilterIterator(new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($lessonContent -> tree), RecursiveIteratorIterator :: SELF_FIRST), array('ctg_type' => 'examples'))) as $key => $value) {
            $exampleIds[$key] = $key;            //Count examples
        }


        $user ? $projects = $this -> getProjects(false, $user, false) : $projects = $this -> getProjects();

        $direction = $this -> getDirection();

        $info['students']      = $this -> getUsers('student');
        $info['professors']    = $this -> getUsers('professor');
        $info['tests']         = sizeof($testIds);
        $info['theory']        = sizeof($theoryIds);
        $info['examples']      = sizeof($exampleIds);
        $info['content']       = $info['examples'] + $info['theory'];
        $info['projects']      = sizeof($projects);
        $info['direction']     = $direction['name'];
        $info['active']        = $this -> lesson['active'];
        $info['active_string'] = $this -> lesson['active'] == 1 ? _YES : _NO;
        $info['price']         = $this -> lesson['price'];
        $info['price_string']  = $this -> lesson['price'] . ' '. $GLOBALS['configuration']['currency'];
        $info['language']      = $this -> lesson['languages_NAME'];
        $info['from_timestamp']= $this -> lesson['from_timestamp'];
        $info['to_timestamp']  = $this -> lesson['to_timestamp'];
        //$info['shift']         = $this -> lesson['shift'];

        if ($this -> lesson['info']) {
            unserialize($this -> lesson['info']) !== false ? $info = array_merge($info, unserialize($this -> lesson['info'])) : $info = array_merge($info, $this -> lesson['info']);
        }

        return $info;
    }

   /**
     * Get lesson statisticsinformation
     *
     * This function returns the lesson information in an array
     * with attributes: 'general_description', 'assessment',
     * 'objectives', 'lesson_topics', 'resources', 'other_info',
     * as well as other information, including professors, projects
     * etc.
     * If a user is specified, the information is customized on this
     * user.
     *
     * <br/>Example:
     * <code>
     * $info = $lesson -> getInformation();         //Get lesson information
     * $info = $lesson -> getInformation('jdoe');   //Get lesson information, customizable for user 'jdoe'
     * </code>
     *
     * @param string $user The user login to customize lesson information for
     * @return array The lesson information
     * @since 3.5.0
     * @access public
     */
    public function getStatisticInformation($user = false) {

        $lessonContent = new EFrontContentTree($this -> lesson['id']);

        $testIds = array();
        foreach (new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($lessonContent -> tree), RecursiveIteratorIterator :: SELF_FIRST), array('active' => 1, 'ctg_type' => 'tests')) as $key => $value) {
            $testIds[$key] = $key;            //Count tests
        }
        foreach (new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($lessonContent -> tree), RecursiveIteratorIterator :: SELF_FIRST), array('active' => 1, 'ctg_type' => 'scorm_test')) as $key => $value) {
            $testIds[$key] = $key;            //Count scorm tests
        }

        $theoryIds = array();
        foreach (new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($lessonContent -> tree), RecursiveIteratorIterator :: SELF_FIRST), array('ctg_type' => 'theory', 'active' => 1)) as $key => $value) {
            $theoryIds[$key] = $key;            //Count theory
        }
        foreach (new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($lessonContent -> tree), RecursiveIteratorIterator :: SELF_FIRST), array('ctg_type' => 'scorm', 'active' => 1)) as $key => $value) {
            $theoryIds[$key] = $key;            //Count scorm content
        }

        $exampleIds = array();
        foreach (new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($lessonContent -> tree), RecursiveIteratorIterator :: SELF_FIRST), array('ctg_type' => 'examples', 'active' => 1)) as $key => $value) {
            $exampleIds[$key] = $key;            //Count examples
        }

        if (!$user) {
            $projects = $this -> getProjects();
            $lessonComments = eF_getTableData("comments, content", "comments.*",
                                              "comments.content_ID = content.id and content.lessons_ID=".$this->lesson['id']);
            $lessonMessages = eF_getTableData("f_messages, f_topics, f_forums", "f_messages.*",
                                              "f_messages.f_topics_ID = f_topics.id and f_topics.f_forums_ID = f_forums.id and f_forums.lessons_ID=".$this->lesson['id']);
            $lessonChat     = eF_getTableData("chatmessages, chatrooms", "chatmessages.*",
                                              "chatmessages.chatrooms_ID = chatrooms.id and chatrooms.lessons_ID = ".$this->lesson['id']);
        } else {
            $projects = $this -> getProjects(false, $user, false);
            $lessonComments = eF_getTableData("comments, content", "comments.*",
                                              "comments.users_LOGIN='".$user."' and comments.content_ID = content.id and content.lessons_ID=".$this->lesson['id']);
            $lessonMessages = eF_getTableData("f_messages, f_topics, f_forums", "f_messages.*",
                                              "f_messages.users_LOGIN='".$user."' and f_messages.f_topics_ID = f_topics.id and f_topics.f_forums_ID = f_forums.id and f_forums.lessons_ID=".$this->lesson['id']);
            $lessonChat     = eF_getTableData("chatmessages, chatrooms", "chatmessages.*",
                                              "chatmessages.users_LOGIN='".$user."' and chatmessages.chatrooms_ID = chatrooms.id and chatrooms.lessons_ID = ".$this->lesson['id']);
        }

        $direction   = $this -> getDirection();
        $languages   = EfrontSystem :: getLanguages(true);
        $info['students']      = $this -> getUsers('student');
        $info['professors']    = $this -> getUsers('professor');
        $info['tests']         = sizeof($testIds);
        $info['theory']        = sizeof($theoryIds);
        $info['examples']      = sizeof($exampleIds);
        $info['content']       = $info['examples'] + $info['theory'];
        $info['projects']      = sizeof($projects);
        $info['comments']      = sizeof($lessonComments);
        $info['messages']      = sizeof($lessonMessages);
        $info['chatmessages']  = sizeof($lessonChat);
        $info['direction']     = $direction['name'];
        $info['active']        = $this -> lesson['active'];
        $info['active_string'] = $this -> lesson['active'] == 1 ? _YES : _NO;
        $info['price']         = $this -> lesson['price'];
        $info['price_string']  = $this -> lesson['price'] . ' '. $GLOBALS['CURRENCYSYMBOLS'][$GLOBALS['configuration']['currency']];
        $info['language']      = $languages[$this -> lesson['languages_NAME']];

        if ($this -> lesson['info']) {
            if (unserialize($this -> lesson['info']) !== false) {
                $info = array_merge($info, unserialize($this -> lesson['info']));
            } else if (is_array($this -> lesson['info'])) {
                $info = array_merge($info, $this -> lesson['info']);
            }
        }
        return $info;
    }


    /**
     * Set lesson information
     *
     * This function sets the lesson information to the designated
     * value. If $info is not set, the lesson information is erased
     * <br/>Example:
     * <code>
     * $info = array('general_description' => 'Hello world');               //Set the new lesson information, erasing any old information
     * $lesson -> setInformation($info);
     * $info = $lesson -> getInformation();                                 //Set new information, keeping old information at the same time
     * $info['assessment'] = 'Goodbye cruel world';
     * $lesson -> setInformation($info);
     * $lesson -> setInformation();                                         //Erase information
     * </code>
     *
     * @param array $info The lesson information
     * @return boolean True if everything is ok
     * @since 3.5.0
     * @access public
     */
    public function setInformation($info = false) {
        if ($info) {
            $info = addslashes(serialize($info));
            $this -> lesson['info'] = $info;
            eF_updateTableData("lessons", array("info" => $info), "id=".$this -> lesson['id']);
        } else {
            $this -> lesson['info'] = '';
            eF_updateTableData("lessons", array("info" => ""), "id=".$this -> lesson['id']);
        }

        return true;
    }

    /**
     * Initialize lesson
     *
     * This function is used to initialize specific aspects of the current lesson
     * These aspects can be the lesson content, announcements, users, glossary etc
     * specified in the $deleteEntities array.
     * <br/>Example:
     * <code>
     * try {
     *   $lesson = new EfrontLesson(32);                     //32 is the lesson id
     *  $lesson -> initialize(array('content', 'glossary', 'rules'));           //Erase all content, glossary terms and content rules
     * } catch (Exception $e) {
     *   echo $e -> getMessage();
     * }
     * </code><br/>
     * If $deleteEntities is 'all', then all lesson aspects are reset
     *
     * @param mixed $deleteEntities Eiterh an array with lesson aspects to initialize, or 'all' which equals to 'reset everything'
     * @return boolean True if everything is ok
     * @since 3.5.0
     * @access public
     */
    public function initialize($deleteEntities) {

        if ($deleteEntities == 'all') {
            $deleteEntities = array('content', 'surveys', 'tracking', 'files',
                                    'conditions', 'calendar', 'periods', 'news',
                                    'glossary', 'users', 'comments', 'rules');
        }

        $content = eF_getTableDataFlat("content", "*", "lessons_ID=".$this -> lesson['id']);                    //Get the lesson units
        sizeof($content['id']) > 0 ? $content_list = implode(",", $content['id']) : $content_list = array();    //Create list of content ids, will come in handy later

        if (in_array('content', $deleteEntities)) {                                                             //Delete lesson units
            foreach ($content['id'] as $value) {
                $value = new EfrontUnit($value);
                $value -> delete();
            }
            $result = eF_getTableDataFlat("content", "id", "lessons_ID=".$this -> lesson['id']);
            $list   = implode(",", $result['id']);
            EfrontSearch :: removeText('content', $list, '', true);
            eF_deleteTableData("content", "lessons_ID=".$this -> lesson['id']);                             //Just make sure everything is deleted
        }
        if (in_array('surveys', $deleteEntities)) {
            $surveys      = eF_getTableDataFlat("surveys", "id", "lessons_ID=".$this -> lesson['id']);
            $surveys_list = implode(",", $surveys['id']);
            eF_deleteTableData("questions_to_surveys",  "surveys_ID IN ($surveys_list)");
            eF_deleteTableData("survey_questions_done", "surveys_ID IN ($surveys_list)");
            eF_deleteTableData("users_to_surveys",      "surveys_ID IN ($surveys_list)");
            eF_deleteTableData("users_to_done_surveys", "surveys_ID IN ($surveys_list)");
            eF_deleteTableData("surveys", "lessons_ID=".$this -> lesson['id']);
        }
        if (in_array('tracking', $deleteEntities)) {
            $tracking_info = array("done_content"       => "",
                                   "issued_certificate" => "",
                                   "comments"           => "",
                                   "completed"          => 0,
                                   "current_unit"       => 0,
                                   "score"              => 0);
            eF_updateTableData("users_to_lessons", $tracking_info, "lessons_ID = ".$this -> lesson['id']);
        }
        if (in_array('files', $deleteEntities)) {
            $filesystem = new FileSystemTree($this -> getDirectory());
            foreach (new ArrayIterator($filesystem -> tree) as $key => $value) {
                $value -> delete();
            }
        }
        in_array('conditions', $deleteEntities) ? eF_deleteTableData("lesson_conditions", "lessons_ID=".$this -> lesson['id']) : null;
        in_array('calendar',   $deleteEntities) ? eF_deleteTableData("calendar",          "lessons_ID=".$this -> lesson['id']) : null;
        in_array('periods',    $deleteEntities) ? eF_deleteTableData("periods",           "lessons_ID=".$this -> lesson['id']) : null;
        in_array('news',       $deleteEntities) ? eF_deleteTableData("news",              "lessons_ID=".$this -> lesson['id']) : null;
        in_array('glossary',   $deleteEntities) ? eF_deleteTableData("glossary_words",    "lessons_ID=".$this -> lesson['id']) : null;
        in_array('users',      $deleteEntities) ? eF_deleteTableData("users_to_lessons",  "lessons_ID=".$this -> lesson['id']." and user_type = 'student'") : null;

        in_array('comments', $deleteEntities) ? eF_deleteTableData("comments", "content_ID IN (".$content_list.")") : null;
        in_array('rules',    $deleteEntities) ? eF_deleteTableData("rules",    "content_ID IN (".$content_list.") or rule_content_ID IN (".$content_list.")") : null;

        $done_tests = eF_getTableDataFlat("done_tests", "id", "tests_ID IN ($content_list)");
        sizeof($done_tests) > 0 ? eF_deleteTableData("done_questions", "done_tests_ID IN (".implode(",", $done_tests['id']).")") : null;
        eF_deleteTableData("done_tests",          "tests_ID IN ($content_list)");
        eF_deleteTableData("users_to_done_tests", "tests_ID IN ($content_list)");
        eF_deleteTableData("logs",                "action='test_begin' AND comments IN ($content_list)");

        // MODULES - Initialize module table data
        // Get all modules (NOT only the ones that have to do with the user type)
        $modules = eF_loadAllModules();
        foreach ($modules as $module) {
            $module -> onDeleteLesson($this -> lesson['id']);
        }

        return true;
    }


    public function toXML($flgContent){
        $str = "";

        //write out general lesson information
        foreach ($lesson as $key => $value){
            $str .= "<$key>$value<$key>";
        }

        //write out the content tree
        $contentTree = new EfrontContentTree($this->lesson['id']);
        $str .= $contentTree->toXML(false);
        //write out the glossary
        $glossary = ef_getTableData("glossary_words","*","lessons_ID=".$this->lessonId);
        if (sizeof($glossary) > 0){
            $str .= '<glossary>';
            for ($i = 0; $i < sizeof($glossary); $i++){
                $str .= '<word>';
                $str .= '<name>'.$glossary[$i]['name'].'</name>';
                $str .= '<info>'.$glossary[$i]['info'].'</info>';
                $str .= '<type>'.$glossary[$i]['type'].'</type>';
                $str .= '<active>'.$glossary[$i]['active'].'</active>';
                $str .= '</word>';
            }
            $str .= '</glossary>';
        }

        //write out the lesson conditions
        $conditions = ef_getTableData("lesson_conditions", "*", "lessons_ID=".$this->lessonId);
        if (sizeof($conditions) > 0){
            $str .= '<conditions>';
            for ($i = 0; $i < sizeof($conditions); $i++){
                $str .= '<condition>';
                $str .= '<type>'.$conditions[$i]['type'].'</type>';
                $str .= '<options>'.$conditions[$i]['options'].'</options>';
                $str .= '<relation>'.$conditions[$i]['relation'].'</relation>';
                $str .= '</condition>';
            }
            $str .= '</conditions>';
        }

        //write out the rules
        $rules = ef_getTableData("rules r, content c", "r.*", "c.id = r.content_ID and c.lessons_ID=".$this->lessonId);
        if (sizeof($rules) > 0){
            $str .= '<rules>';
            for ($i = 0; $i < sizeof($rules); $i++){
                $str .= "<rule>";
                $str .= "<content_id>".$rules[$i]['content_ID']."</content_id>";
                $str .= "<rule_content_id>".$rules[$i]['rule_content_ID']."</rule_content_id>";
                $str .= "<rule_type>".$rules[$i]['rule_type']."</rule_type>";
                $str .= "<rule_option>".$rules[$i]['rule_option']."</rule_option>";
                $str .= '</rules>';
            }
            $str .= '</rules>';
        }

        if ($flgContent){
            //to do export the content as well
        }

        $xmlstr .= '<?xml version="1.0" encoding="UTF-8"?><lesson>'.$str.'</lesson>';
        return $xmlstr;
    }

    public function fromXML($xmlfile){
        $xml = simplexml_load_file($xmlfile);
        $contentTree = new EfrontContentTree($this->lesson['id']);
        $contentTree -> fromXMLNode($xml->lessonId[0]);
        $fields = array();
        $fields['name'] = (string)$xml->lesson->name;
        $fields['info'] = (string)$xml->lesson->info;
        $fields['options'] = (string)$xml->lesson->options;
        $fields['course_only'] = (string)$xml->lesson->course_only;
        //$fields['auto_certificate'] = (string)$xml->lesson->auto_certificate;
        //$fields['auto_complete'] = (string)$xml->lesson->auto_complete;
        //$fields['publish'] = (string)$xml->lesson->publish;
        $lid = ef_inserTableData("lessons", $fields);

        for ($i = 0; $i < sizeof($xml->lesson->conditions->condition); $i++){
            $condition = array();
            $condition['type'] = $xml->lessonId->conditions->condition[$i]->type;
            $condition['options'] = $xml->lessonId->conditions->condition[$i]->options;
            $condition['relation'] = $xml->lessonId->conditions->condition[$i]->relation;
            $cid = ef_insertTableData("lesson_conditions", $condition);
        }

        for ($i = 0; $i < sizeof($xml->lesson->rules->rule); $i++){
            $rule = array();
            $rule['content_id'] = $xml->lessonId->rules->rule[$i]->content_id;
            $rule['rule_content_id'] = $xml->lessonId->rules->rule[$i]->rule_content_id;
            $rule['rule_type'] = $xml->lessonId->rules->rule[$i]->rule_type;
            $rule['rule_option'] = $xml->lessonId->rules->rule[$i]->rule_option;
            $rid = ef_insertTableData("rules", $rule);
        }
    }

    public function toIMS($path){
        $lesson_entries = eF_getTableData("content", "id, name, data", "lessons_ID=" . $this->lesson['id'] . " and ctg_type = 'theory' and active=1");

        $cur_dir = getcwd();
        chdir(G_LESSONSPATH.$this->lesson['id'].'/');
        $filelist = eF_getDirContents();
        chdir($cur_dir);

        create_manifest($this->lesson['id'], $lesson_entries, $filelist, $path);


        //create the EfrontLesson.xml
        $str = '<?xml version="1.0" encoding="UTF-8"?><efrontlesson>';
        //write out the glossary
        $glossary = ef_getTableData("glossary_words","*","lessons_ID=".$this->lesson['id']);
        if (sizeof($glossary) > 0){
            $str .= '<glossary>';
            for ($i = 0; $i < sizeof($glossary); $i++){
                $str .= '<word>';
                $str .= '<name>'.$glossary[$i]['name'].'</name>';
                $str .= '<info>'.$glossary[$i]['info'].'</info>';
                $str .= '<type>'.$glossary[$i]['type'].'</type>';
                $str .= '<active>'.$glossary[$i]['active'].'</active>';
                $str .= '</word>';
            }
            $str .= '</glossary>';
        }

        //write out the lesson conditions
        $conditions = ef_getTableData("lesson_conditions", "*", "lessons_ID=".$this->lesson['id']);
        if (sizeof($conditions) > 0){
            $str .= '<conditions>';
            for ($i = 0; $i < sizeof($conditions); $i++){
                $str .= '<condition>';
                $str .= '<type>'.$conditions[$i]['type'].'</type>';
                $str .= '<options>'.$conditions[$i]['options'].'</options>';
                $str .= '<relation>'.$conditions[$i]['relation'].'</relation>';
                $str .= '</condition>';
            }
            $str .= '</conditions>';
        }

        //write out the rules
        $rules = ef_getTableData("rules r, content c", "r.*", "c.id = r.content_ID and c.lessons_ID=".$this->lesson['id']);
        if (sizeof($rules) > 0){
            $str .= '<rules>';
            for ($i = 0; $i < sizeof($rules); $i++){
                $str .= "<rule>";
                $str .= "<content_id>".$rules[$i]['content_ID']."</content_id>";
                $str .= "<rule_content_id>".$rules[$i]['rule_content_ID']."</rule_content_id>";
                $str .= "<rule_type>".$rules[$i]['rule_type']."</rule_type>";
                $str .= "<rule_option>".$rules[$i]['rule_option']."</rule_option>";
                $str .= '</rule>';
            }
            $str .= '</rules>';
        }

        //write out the questions
        $questions = ef_getTableData("questions q, content c", "q.*", "q.content_id = c.id and c.lessons_id=".$this->lesson['id']."");
        if (sizeof($questions) > 0){
            $str .= "<questions>";
            for ($i = 0; $i < sizeof($questions); $i++){
                $str .= "<question>";
                $str .= "<refid>q".$questions[$i]['id']."</refid>";
                $str .= "<type>".$questions[$i]['type']."</type>";
                $str .= "<difficulty>".$questions[$i]['difficulty']."</difficulty>";
                $str .= "<options>".$questions[$i]['options']."</options>";
                $str .= "<answer>".$questions[$i]['answer']."</answer>";
                $str .= "<explanation>".$questions[$i]['explanation']."</explanation>";
                $str .= "</question>";
            }
            $str .= "</questions>";
        }

        //write out the tests
        $tests = ef_getTableData("tests t, content c", "t.*", "t.content_id = c.id and c.lessons_id=".$this->lesson['id']."");
        if (sizeof($tests) > 0){
            $str .= "<tests>";
            for ($i = 0; $i < sizeof($tests); $i++){
                $str .= "<test>";
                $str .= "<refid>t".$tests[$i]['id']."</refid>";
                $str .= "<duration>".$tests[$i]['duration']."</duration>";
                $str .= "<redoable>".$tests[$i]['redoable']."</redoable>";
                $str .= "<onebyone>".$tests[$i]['onebyone']."</onebyone>";
                $str .= "<answers>".$tests[$i]['answers']."</answers>";
                $str .= "<shuffle_questions>".$tests[$i]['shuffle_questions']."</shuffle_questions>";
                $str .= "<shuffle_answers>".$tests[$i]['shuffle_answers']."</shuffle_answers>";
                $str .= "<given_answers>".$tests[$i]['given_answers']."</given_answers>";
                $questions = ef_getTableData("tests_to_questions","*","tests_ID = ".$tests[$i]['id']);
                $str .= "<questions>";
                for ($j = 0; $j < sizeof($questions); $j++){
                    $str .= "<question>";
                    $str .= "<refid>q".$questions[$j]['questions_ID']."</refid>";
                    $str .= "<weight>".$questions[$j]['weight']."</weight>";
                    $str .= "<previous>q".$questions[$j]['previous_question_ID']."</previous>";
                    $str .= "</question>";
                }
                $str .= "</questions>";
                $str .= "</test>";
            }
            $str .= "</tests>";
        }

        $str .= '</efrontlesson>';
        if ($fp = fopen($path . "/lesson".$this->lesson['id']."/eFrontLesson.xml", "wb")) {
          fwrite($fp, $str);
        }
        fclose($fp);


        chdir($path."/lesson". $this->lesson['id']);
        $d = dir(".");
        $entries = array();
        while (false !== ($entry = $d->read())) {
            if ($entry != "." & $entry != ".."){
                array_push($entries, $entry);
            }
        }
        $d->close();
        $zip = new Archive_zip($path."/lesson".$this->lesson['id'].".tar.gz");
        $zip -> create( $entries );
        chdir($cur_dir);
        deldir($path."/lesson". $this->lesson['id']);
    }

    public function fromIMS($ims_file, $deleteEntities = false){

        if ($deleteEntities) {
            $this -> initialize($deleteEntities);               //Initialize the lesson aspects that the user specified
        }
        $timestamp       = time();
        $zip  = new Archive_zip($ims_file);
        $extracted_files = $zip -> extract(array('add_path' => G_LESSONSPATH.$this->lesson['id']."/IMS_".$timestamp));
        $total_fields = array();
        $resources    = array();
        $tagArray     = @eF_local_parseManifest(G_LESSONSPATH.$this->lesson['id']."/IMS_".$timestamp);
        $questions = array();
        $tests = array();
        $content = array();
        $inContent = false;
        $inTest = false;
        $inQuestion = false;
        $references = array();
        $questionsKeys = array();
        $testsKeys = array();
        foreach($tagArray as $key => $value) {
            $fields = array();
            switch ($value['tag']) {
                case 'TITLE':
                    $cur = $value['parent_index'];
                    if ($inContent){
                        $content[$cur]['name'] = $value['value'];
                    }
                    if ($inTest){
                        $tests[$cur]['name'] = $value['value'];
                    }
                    break;

                case 'ITEM':
                    $cur = $key;
                    if ($value['attributes']['TYPE'] != 'question' && $value['attributes']['TYPE'] != 'test')
                    {
                        $inContent = true;
                        $inTest = false;
                        $inQuestion = false;
                        $content[$key]['lessons_ID'] = $this->lesson['id'];
                        $content[$key]['timestamp']  = time();
                        $content[$key]['ctg_type']   = 'theory';
                        $content[$key]['active']     = 1;
                        $references[$key] = $value['attributes']['IDENTIFIERREF'];
                    }
                    else if ($value['attributes']['TYPE'] == 'test')
                    {
                        $inTest = true;
                        $inContent = false;
                        $inQuestion = false;
                        $tests[$key]['active'] = '1';
                        $testsKeys[$value['attributes']['IDENTIFIERREF']] = $key;
                        $references[$key] = $value['attributes']['IDENTIFIERREF'];
                    }
                    else if ($value['attributes']['TYPE'] == 'question')
                    {
                        $inQuestion = true;
                        $inContent = false;
                        $inTest = false;
                        $questions[$key]['difficulty'] = 'medium'; //initial value
                        $questions[$key]['type'] = 'true_false'; //initial value
                        $questions[$key]['timestamp'] = time();
                        $questionsKeys[$value['attributes']['IDENTIFIERREF']] = $key;
                        $references[$key] = $value['attributes']['IDENTIFIERREF'];
                    }
                    break;

                case 'RESOURCE':
                    $resources[$key] = $value['attributes']['IDENTIFIER'];
                    break;

                case 'FILE':
                    $files[$key] = $value['attributes']['HREF'];
                    break;

                case 'ADLCP:MAXTIMEALLOWED':
                    $maxtimeallowed[$key]  = $value['value'];
                    break;
                case 'ADLCP:TIMELIMITACTION':
                    $timelimitaction[$key] = $value['value'];
                    break;
                case 'ADLCP:MASTERYSCORE':
                    $masteryscore[$key]    = $value['value'];
                    break;
                case 'ADLCP:DATAFROMLMS':
                    $datafromlms[$key]     = $value['value'];
                    break;

                case 'ADLCP:PREREQUISITES':
                    $prerequisites[$key]   = $value['value'];
                    break;

                default:
                    break;
            }
        }

        foreach ($references as $key => $value) {

            $ref = array_search($value, $resources);
            if ($ref) {

                $data = file_get_contents(G_LESSONSPATH.$this->lesson['id']."/IMS_".$timestamp."/".$tagArray[$ref]['attributes']['HREF']);


                $primitive_hrefs[$ref] = $tagArray[$ref]['attributes']['HREF'];
                $path_part[$ref]       = dirname($primitive_hrefs[$ref]);


                foreach($tagArray[$ref]['children'] as $value2) {

                    if ($tagArray[$value2]['tag'] == 'DEPENDENCY') {

                        $idx = array_search($tagArray[$value2]['attributes']['IDENTIFIERREF'], $resources);


                        foreach ($tagArray[$idx]['children'] as $value3) {

                            if ($tagArray[$value3]['tag'] == 'FILE')  {

                                $data = preg_replace("#(\.\.\/(\w+\/)*)?".$tagArray[$value3]['attributes']['HREF']."#", G_LESSONSPATH.$this->lesson['id']."/".$path_part[$ref]."/$1".$tagArray[$value3]['attributes']['HREF'], $data);
                            }
                        }
                    }
                }

                if ($content[$key]['active'] == 1){
                    $i1 = stripos($data, "<body");
                    $i2 = stripos($data, ">", $i1);
                    $i3 = strripos($data, "<script");
                    $data = substr($data, $i2 + 1, $i3 - $i2 - 1);
                    $content[$key]['data'] = $data;
                }
                else if ($tests[$key]){
                    $data = $data;
                    $tests[$key]['description'] = $data;
                }
                else if ($questions[$key]){
                    $data = $data;
                    $questions[$key]['text'] = $data;
                }
            }
        }

        $inStart = true;
        foreach ($content as $key => $value){
            $cid = ef_insertTableData("content", $value);
            /* TODO INDEX */
            if ($inStart){
                $inStart = false;
                foreach ($questions as $keyq => $valueq){
                    $questions[$keyq]['content_ID'] = $cid;
                }
            }
        }


        foreach ($questions as $key => $value){
            $qid = ef_insertTableData("questions", $value);
            $questions[$key]['id'] = $qid;
        }

        foreach ($tests as $key => $value){
            $test_content['lessons_ID'] = $this->lesson['id'];
            $test_content['timestamp']  = time();
            $test_content['ctg_type']   = 'tests';
            $test_content['active']     = 1;
            $test_content['name'] = $value['name'];
            unset($value['name']);
            $cid = ef_insertTableData("content", $test_content);
            $value['content_id'] = $cid;
            $tid = ef_insertTableData("tests", $value);
            $tests[$key]['id'] = $tid;
        }


        eF_local_buildDirectories(G_LESSONSPATH.$this->lesson['id']."/", G_LESSONSPATH.$this->lesson['id']."/IMS_".$timestamp);

        foreach ($files as $key => $value) {

    //      if (!in_array($value, $primitive_hrefs))
    //      {
                $newhref = $tagArray[$tagArray[$key]['parent_index']]['attributes']['XML:BASE'];
                //copy(G_LESSONSPATH.$this->lesson['id']."/IMS_".$timestamp."/".trim($newhref,"/")."/".trim($value,"/"), G_LESSONSPATH.$this->lesson['id']."/".trim($newhref,"/")."/".trim($value,"/"));
    //      }
        }

        $cur_dir = getcwd();
        chdir(G_LESSONSPATH.$this->lesson['id']."/IMS_".$timestamp);
        $filelist = eF_getDirContents();
        foreach ($filelist as $value) {
            copy($value, G_LESSONSPATH.$this->lesson['id']."/".$value);
        }
        chdir($cur_dir);


        foreach ($prerequisites as $key => $value) {
            foreach ($tagArray as $key2 => $value2) {
                if (isset($value2['attributes']['IDENTIFIER']) && $value2['attributes']['IDENTIFIER'] == $value) {
                    unset($fields_insert);
                    $fields_insert['users_LOGIN'] = "*";
                    $fields_insert['content_ID']  = $tagArray[$tagArray[$key]['parent_index']]['this_id'];
                    $fields_insert['rule_type']   = "hasnot_seen";
                    $fields_insert['rule_content_ID'] = $value2['this_id'];
                    $fields_insert['rule_option'] = 0;
                    //eF_insertTableData("rules", $fields_insert);
                }
            }
        }

        //read the special EfrontLesson.xml
        $xmlfile = G_LESSONSPATH.$this->lesson['id']."/IMS_".$timestamp."/EfrontLesson.xml";
        $xml = simplexml_load_file($xmlfile);
        for ($i = 0; $i < sizeof($xml->conditions->condition); $i++){
            $condition = array();
            $condition['type'] = (string)$xml->conditions->condition[$i]->type;
            $condition['options'] = (string)$xml->conditions->condition[$i]->options;
            $condition['relation'] = (string)$xml->conditions->condition[$i]->relation;
            $condition['lessons_ID'] = $this->lesson['id'];
            $cid = ef_insertTableData("lesson_conditions", $condition);
        }
        for ($i = 0; $i < sizeof($xml->glossary->word); $i++){
            $glossary = array();
            $glossary['name'] = (string)$xml->glossary->word[$i]->name;
            $glossary['type'] = (string)$xml->glossary->word[$i]->type;
            $glossary['info'] = (string)$xml->glossary->word[$i]->info;
            $glossary['active'] = (string)$xml->glossary->word[$i]->active;
            $glossary['lessons_ID'] = $this->lesson['id'];
            $cid = ef_insertTableData("glossary_words", $glossary);
        }

        for ($i = 0; $i < sizeof($xml->questions->question); $i++){
            $update = array();
            $refid = (string)$xml->questions->question[$i]->refid;
            $qk = $questionsKeys[$refid];
            $qid = $questions[$qk]['id'];
            $update['type'] = (string)$xml->questions->question[$i]->type;
            $update['difficulty'] = (string)$xml->questions->question[$i]->difficulty;
            $update['options'] = (string)$xml->questions->question[$i]->options;
            $update['answer'] = (string)$xml->questions->question[$i]->answer;
            $update['explanation'] = (string)$xml->questions->question[$i]->explanation;
            ef_updateTableData("questions", $update, "id = $qid");
        }

        for ($i = 0; $i < sizeof($xml->tests->test); $i++){
            $update = array();
            $refid = (string)$xml->tests->test[$i]->refid;
            $tk = $testsKeys[$refid];
            $tid = $tests[$tk]['id'];
            $update['duration'] = (string)$xml->tests->test[$i]->duration;
            $update['redoable'] = (string)$xml->tests->test[$i]->redoable;
            $update['onebyone'] = (string)$xml->tests->test[$i]->onebyone;
            $update['answers'] = (string)$xml->tests->test[$i]->answers;
            $update['shuffle_questions'] = (string)$xml->tests->test[$i]->shuffle_questions;
            $update['shuffle_answers'] = (string)$xml->tests->test[$i]->shuffle_answers;
            $update['given_answers'] = (string)$xml->tests->test[$i]->given_answers;
            ef_updateTableData("tests", $update, "id=".$tid);
            for ($j = 0; $j < sizeof($xml->tests->test[$i]->questions->question); $j++){
                $testQuestions = array();
                $refid = (string)$xml->tests->test[$i]->questions->question[$j]->refid;
                $qk = $questionsKeys[$refid];
                $qid = $questions[$qk]['id'];
                $previd = (string)$xml->tests->test[$i]->questions->question[$j]->previous;
                if ($previd != "q0"){
                    $pk = $questionsKeys[$previd];
                    $pid = $questions[$pk]['id'];
                }
                else
                    $pid = 0;
                $testQuestions['tests_ID'] = $tid;
                $testQuestions['questions_ID'] = $qid;
                $testQuestions['previous_question_ID'] = $pid;
                $testQuestions['weight'] = (string)$xml->tests->test[$i]->questions->question[$j]->weight;
                ef_insertTableData("tests_to_questions", $testQuestions);
            }
        }
    }

    /**
     * Import lesson
     *
     * This function is used to import a lesson exported to a file
     * The first step is to optionally initialize the lesson, using initialize().
     * It then uncompresses the given file and proceeds to importing
     * <br/>Example:
     * <code>
     * try {
     *     $lesson = new EfrontLesson(32);                                             //32 is the lesson id
     *     $file = new EfrontFile($lesson -> getDirectory().'data.tar.gz');            //The file resides inside the lesson directory and is called 'data.tar.gz'
     *     $lesson -> import(array('content'), $file);
     * } catch (Exception $e) {
     *     echo $e -> getMessage();
     * }
     * </code><br/>
     *
     * @param EfrontFile $file The compressed lesson file object
     * @param array $deleteEntities The lesson aspects to initialize
     * @return boolean True if the importing was successful
     * @since 3.5.0
     * @access public
     * @see EfrontLesson :: initialize()"
     */
    public function import($file, $deleteEntities = false) {

        if ($deleteEntities) {
            $this -> initialize($deleteEntities);               //Initialize the lesson aspects that the user specified
        }

        $fileList = $file -> uncompress();
        $file -> delete();

        $fileList = array_unique(array_reverse($fileList, true));
        $dataFile = new EfrontFile($this -> directory.'data.dat');
        $filedata = file_get_contents($dataFile['path']);
        $dataFile -> delete();

        $data              = unserialize($filedata);

        $data['content']   = self :: eF_import_fixTree($data['content'], $last_current_node);

        for ($i = 0; $i < sizeof($data['files']); $i++) {
            if (isset($data['files'][$i]['file'])) {
                $newName = str_replace(G_ROOTPATH, '', dirname($data['files'][$i]['file']).'/'.EfrontFile :: encode(basename($data['files'][$i]['file'])));
                $newName = preg_replace("#(.*)www/content/lessons/#", "www/content/lessons/", $newName);
                $newName = preg_replace("#www/content/lessons/\d+/(.*)#", "www/content/lessons/".$this -> lesson['id']."/\$1", $newName);
                if ($data['files'][$i]['original_name'] != basename($data['files'][$i]['file'])) {
                    if (is_file(G_ROOTPATH.$newName)) {
                        $replaceString['/\/?(view_file.php\?file=)'.$data['files'][$i]['id'].'([^0-9])/'] = '${1}'.array_search(G_ROOTPATH.$newName, $fileList).'${2}';    //Replace old ids with new ids
                        //$mp[$data['files'][$i]['id']] = array_search(G_ROOTPATH.$newName, $fileList);
                        $file = new EfrontFile(G_ROOTPATH.$newName);
                        $file -> rename(G_ROOTPATH.dirname($newName).'/'.EfrontFile :: encode(rtrim($data['files'][$i]['original_name'], "/")));
                    }
                }
            } else {
                $newName = preg_replace("#www/content/lessons/\d+/(.*)#", "www/content/lessons/".$this -> lesson['id']."/\$1", $data['files'][$i]['path']);
                if (is_file(G_ROOTPATH.$newName)) {
                    $replaceString['/\/?(view_file.php\?file=)'.$data['files'][$i]['id'].'([^0-9])/'] = '${1}'.array_search(G_ROOTPATH.$newName, $fileList).'${2}';    //Replace old ids with new ids
                }
            }
        }

        for ($i = 0; $i < sizeof($data['files']); $i++) {
            if (isset($data['files'][$i]['file'])) {
                $newName = str_replace(G_ROOTPATH, '', dirname($data['files'][$i]['file']).'/'.EfrontFile :: encode(basename($data['files'][$i]['file'])));
                $newName = preg_replace("#(.*)www/content/lessons/#", "www/content/lessons/", $newName);
                $newName = preg_replace("#www/content/lessons/\d+/(.*)#", "www/content/lessons/".$this -> lesson['id']."/\$1", $newName);
                if ($data['files'][$i]['original_name'] != basename($data['files'][$i]['file'])) {
                    if (is_dir(G_ROOTPATH.$newName)) {
                        $file = new EfrontDirectory(G_ROOTPATH.$newName);
                        $file -> rename(G_ROOTPATH.dirname($newName).'/'.EfrontFile :: encode(rtrim($data['files'][$i]['original_name'], "/")));
                    }
                }
            }
        }

        unset($data['files']);

        $last_current_node = 0;
        $existing_tree     = eF_getContentTree($nouse, $this -> lesson['id'], 0, false, false);
        if (sizeof($existing_tree) > 0) {
            $last_current_node = $existing_tree[sizeof($existing_tree) - 1]['id'];
            $first_node        = self :: eF_import_getTreeFirstChild($data['content']);

            $data['content'][$first_node]['previous_content_ID'] = $last_current_node;
        }


        // MODULES - Import module data
        // Get all modules (NOT only the ones that have to do with the user type)
        $modules = eF_loadAllModules();
        foreach ($modules as $module) {
            if (isset($data[$module->className])) {
                $module -> onImportLesson($this -> lesson['id'], $data[$module->className]);
                unset($data[$module->className]);
            }
        }


        foreach ($data as $table => $tabledata) {
            if ($table == "lessons") { //from v3 lessons parameters also imported
                eF_updateTableData("lessons", array('info'      => $data['lessons']['info'],
                                                    'metadata'  => $data['lessons']['metadata'],
                                                    'options'   => $data['lessons']['options'],
                ), "id=".$this -> lesson['id']);
            } else {
                for ($i = 0; $i < sizeof($tabledata); $i++) {
                    $sql = "INSERT INTO ".$table." SET ";
                    $connector = "";
                    foreach ($tabledata[$i] as $key => $value) {
                        if ($key == "id") {
                            $old_id = $value;
                        } else {
                            if (($table == "content" AND $key == "data") || ($table == "questions" AND $key == "text") || ($table == "tests" AND $key == "description")) {
                                $value = str_replace("##SERVERNAME##", "", $value);
                                $value = str_replace("/##LESSONSLINK##", "content/lessons/".$this -> lesson['id'], $value);
                                $value = str_replace("##LESSONSLINK##", "content/lessons/".$this -> lesson['id'], $value);
                                $content_data = $value;
                            }
                            elseif ($key == "lessons_ID") {
                                $value = $this -> lesson['id'];
                            }elseif ($table == "lesson_conditions" AND $key == "options") {
                                if (mb_strpos($data['lesson_conditions'][$i]['type'], "specific") === false){

                                }else{
                                    $options = unserialize($data['lesson_conditions'][$i]['options']);
                                    $options[0] = $map['content'][$options[0]];
                                    $value = serialize($options);

                                }
                            }
                            elseif ($table != "content" AND mb_substr($key, -3) == "_ID") {
                                $from_table = mb_substr($key, 0, -3);
                                if (isset($map[$from_table][$value])) {
                                    $value = $map[$from_table][$value];
                                }
                            }
                            if (!($table == "content" AND $key == "format")) {
                                $sql .= $connector.$key."='".str_replace("'","''",$value)."'";
                                $connector = ", ";
                            }
                            if ($table == "content" AND $key == "name") {
                                $content_name = $value;
                            }
                        }
                    }

                    eF_executeNew($sql);
                    $new_id = mysql_insert_id();
                    //$GLOBALS['db']->debug=true;
                    if ($table == "content") {
                        EfrontSearch :: insertText($content_name, $new_id, "content", "title");
                        EfrontSearch :: insertText(strip_tags($content_data), $new_id, "content", "data");
                    }
                    $map[$table][$old_id] = $new_id;
                }
            }
        }

        if ($data['content']) {
            foreach($map['content'] as $old_id => $new_id) {
                eF_updateTableData("content", array('parent_content_ID' => $new_id), "parent_content_ID=$old_id AND lessons_ID=".$this -> lesson['id']);
                eF_updateTableData("content", array('previous_content_ID' => $new_id), "previous_content_ID=$old_id AND lessons_ID=".$this -> lesson['id']);
            }
        }

        if ($data['rules']) {
            foreach($map['content'] as $old_id => $new_id) {
                eF_updateTableData("rules", array('rule_content_ID' => $new_id), "rule_content_ID=$old_id");
            }
        }

        if ($data['questions']) {
            foreach($map['questions'] as $old_id => $new_id) {
                eF_updateTableData("tests_to_questions", array('previous_question_ID' => $new_id), "previous_question_ID=$old_id");
            }
        }

        foreach ($map['content'] as $old_id => $new_id) {  //needs debugging
            $content_new_IDs[] = $new_id;
        }
        $content_new_IDs_list = implode(",",$content_new_IDs);
        $content_data = eF_getTableData("content", "data,id", "id IN ($content_new_IDs_list) AND lessons_ID=".$this -> lesson['id']);

        if (isset($replaceString)) {
            for ($i = 0; $i < sizeof($content_data); $i++) {
                $replaced = preg_replace(array_keys($replaceString), array_values($replaceString), $content_data[$i]['data']);

                eF_updateTableData("content", array('data' => addslashes($replaced)), "id=".$content_data[$i]['id']);
                EfrontSearch :: removeText('content', $content_data[$i]['id'], 'data');                                     //Refresh the search keywords
                EfrontSearch :: insertText($replaced, $content_data[$i]['id'], "content", "data");
            }
        }

        $content_data  = eF_getTableData("content", "data,id", "id IN ($content_new_IDs_list) AND lessons_ID=".$this -> lesson['id']." AND data like '%##EFRONTINNERLINK##%'");
        for($i =0; $i < sizeof($content_data); $i++) {
            $ok = ereg ("[##EFRONTINNERLINK##.php?ctg=content&amp;view_unit=]([0-9]+)", $content_data[$i]['data'], $regs);
            $replaced   = str_replace("##EFRONTINNERLINK##.php?ctg=content&amp;view_unit=".$regs[1],"##EFRONTINNERLINK##.php?ctg=content&amp;view_unit=".$map["content"][$regs[1]], $content_data[$i]['data']);
            eF_updateTableData("content", array('data' => $replaced), "id=".$content_data[$i]['id']);
            EfrontSearch :: removeText('content', $content_data[$i]['id'], 'data');                                     //Refresh the search keywords
            EfrontSearch :: insertText($replaced, $content_data[$i]['id'], "content", "data");
        }

        return true;

    }

    /**
     * Fix efront v1.x trees
     *
     * This function is used for fixing lessons from efront version 1 that
     * are beeing imported to the system
     *
     * @param array $tree The old content tree
     * @param int $last_current_node The last current node
     * @return array The fixed tree
     * @since 3.5.0
     * @access private
     */
    private function eF_import_fixTree($tree, $last_current_node = 0)
    {
        for ($i = 0; $i < sizeof($tree); $i++) {
            if ($tree[$i]['parent_content_ID'] == 0) {
                $roots[$i] = $tree[$i];
                $roots[$i]['idx'] = $i;
            }
        }

        foreach ($roots as $key => $node) {
            $roots[$key]['last_child'] = self :: eF_import_getLastChild($tree, $key);
            if ($node['previous_content_ID'] == 0 && $node['parent_content_ID'] == 0) {
                $eligible[] = $roots[$key];
            }
        }

        foreach ($eligible as $key => $node) {
            $timestamps[] = $node['timestamp'];
            $found = true;
            $temp = $roots;

            $eligible[$key]['final_child'] = $node['last_child'];
            while (sizeof($temp) > 0 && $found) {
                $found = false;
                foreach ($temp as $temp_key => $temp_node) {
                    if ($eligible[$key]['final_child'] == $temp_node['previous_content_ID']) {
                        $eligible[$key]['final_child'] = $temp_node['last_child'];
                        unset($temp[$temp_key]);

                        $found = true;
                    }
                }
            }
        }

        array_multisort($timestamps, SORT_ASC, $eligible);

        for ($i = 0; $i < sizeof($eligible); $i++) {
            if ($i < sizeof($eligible) - 1) {
                $eligible[$i + 1]['previous_content_ID'] = $eligible[$i]['final_child'];
            }
            unset($eligible[$i]['last_child']);
            unset($eligible[$i]['final_child']);
            $idx = $eligible[$i]['idx'];
            unset($eligible[$i]['idx']);
            $tree[$idx] = $eligible[$i];
        }

        return $tree;
    }

    /**
     * Get the tree last child
     *
     * This function is used for importing lessons and returns the tree's last child
     *
     * @param array $tree The content tree
     * @param int $idx The current index
     * @return int The last children index
     * @since 3.5.0
     * @access private
     */
    private function eF_import_getLastChild($tree, $idx) {
        $original_tree = $tree;

        $count = 0;
        $children[$idx] = $tree[$idx]['id'];
        $found = true;
        while (sizeof($tree) > 0 && $count++ < 1000 && $found) {
            $found = false;
            foreach ($tree as $key => $node) {
                if (in_array($node['parent_content_ID'], $children)) {
                    $children[$key] = $node['id'];
                    unset($tree[$key]);
                    $found = true;
                }
            }
        }

        foreach ($children as $key => $child) {
            $previous[] = $original_tree[$key]['previous_content_ID'];
        }

        $last = (array_diff($children, $previous));
        $last = array_values($last);

        return $last[0];
    }

    /**
     * Get the first child of the tree
     *
     * This function is used for importing lessons and returns the tree's first child
     *
     * @param array $tree
     * @return int the first child index
     * @since 3.5.0
     * @access private
     */
    private function eF_import_getTreeFirstChild($tree)
    {
        $count = 0;
        while ($tree[$count]['parent_content_ID'] != 0 || $tree[$count]['previous_content_ID'] != 0)
        {
            $count++;
        }

        $first_node = $count;
        return $first_node;
    }

    /**
     * Export lesson
     *
     * This function is used to export the current lesson's data to
     * a file, which can then be imported to other systems. Apart from
     * the lesson content, the user may optinally specify additional
     * information to export, using the $exportEntities array. If
     * $exportEntities is 'all', everything that can be exported, is
     * exported
     *
     * <br/>Example:
     * <code>
     * $exportedFile = $lesson -> export('all');
     * </code>
     *
     * @param array $exportEntities The additional data to export
     * @return EfrontFile The object of the exported data file
     * @since 3.5.0
     * @access public
     */
    public function export($exportEntities) {

        if (!$exportEntities == 'all') {
            $exportEntities = array('export_surveys', 'export_announcements', 'export_glossary',
                                    'export_calendar', 'export_periods', 'export_comments', 'export_rules');
        }

        if (is_file($this -> directory.'data.tar.gz')) {
            try {
                $file = new EfrontFile($this -> directory.'data.tar.gz');
                $file -> delete();
            } catch (EfrontFileException $e) {
                unlink($this -> directory.'data.tar.gz');
            }
        }

        $data['lessons'] = $this -> lesson;
        $content         = eF_getTableData("content", "*", "lessons_ID=".$this -> lesson['id']);
        if (sizeof($content) > 0) {
            for ($i = 0; $i < sizeof($content); $i++) {
                $content[$i]['data'] = str_replace(G_SERVERNAME, "##SERVERNAME##", $content[$i]['data']);
                $content[$i]['data'] = str_replace("content/lessons/".$this -> lesson['id'], "##LESSONSLINK##", $content[$i]['data']);
            }
            $content_list    = eF_makeListIDs($content);
            $data['content'] = $content;

            $questions = eF_getTableData("questions", "*", "content_ID IN ($content_list)");
            if (sizeof($questions) > 0) {
                for ($i = 0; $i < sizeof($questions); $i++) {
                    $questions[$i]['text'] = str_replace(G_SERVERNAME, "##SERVERNAME##", $questions[$i]['text']);
                    $questions[$i]['text'] = str_replace("content/lessons/".$this -> lesson['id'], "##LESSONSLINK##", $questions[$i]['text']);
                }
                $data['questions'] = $questions;
            }

            $tests = eF_getTableData("tests", "*", "content_ID IN ($content_list)");
            if (sizeof($tests)) {
                $tests_list         = eF_makeListIDs($tests);
                $tests_to_questions = eF_getTableData("tests_to_questions", "*", "tests_ID IN ($tests_list)");
                for ($i = 0; $i < sizeof($tests); $i++) {
                    $tests[$i]['description'] = str_replace(G_SERVERNAME, "##SERVERNAME##", $tests[$i]['description']);
                    $tests[$i]['description'] = str_replace("content/lessons/".$this -> lesson['id'], "##LESSONSLINK##", $tests[$i]['description']);
                }

                $data['tests']      = $tests;
                $data['tests_to_questions'] = $tests_to_questions;
            }
            if (isset($exportEntities['export_rules'])) {
                $rules = eF_getTableData("rules", "*", "content_ID IN ($content_list)");
                if (sizeof($rules) > 0) {
                    $data['rules'] = $rules;
                }
            }
            if (isset($exportEntities['export_comments'])) {
                $comments = eF_getTableData("comments", "*", "content_ID IN ($content_list)");
                if (sizeof($comments) > 0) {
                    $data['comments'] = $comments;
                }
            }

        }
        if (isset($exportEntities['export_calendar'])) {
            $calendar = eF_getTableData("calendar", "*", "lessons_ID=".$this -> lesson['id']);
            if (sizeof($calendar) > 0) {
                $data['calendar'] = $calendar;
            }
        }

        if (isset($exportEntities['export_glossary'])) {
            $glossary_words = eF_getTableData("glossary_words", "*", "lessons_ID=">$this -> lesson['id']);
            if (sizeof($glossary_words) > 0) {
                $data['glossary_words'] = $glossary_words;
            }
        }

        if (isset($exportEntities['export_announcements'])) {
            $news = eF_getTableData("news", "*", "lessons_ID=".$this -> lesson['id']);
            if (sizeof($news) > 0) {
                $data['news'] = $news;
            }
        }

        if (isset($exportEntities['export_surveys'])) {
            $surveys = eF_getTableData("surveys", "*", "lessons_ID=".$this -> lesson['id']);   //prepei na ginei to   lesson_ID -> lessons_ID sti basi (ayto isos to parampsoyme eykola)
            if (sizeof($surveys) > 0) {
                $data['surveys'] = $surveys;
                $surveys_list    = eF_makeListIDs($surveys);

                $questions_to_surveys = eF_getTableData("questions_to_surveys", "*", "surveys_ID IN ($surveys_list)");  // oposipote omos to survey_ID -> surveys_ID sti basi
                if (sizeof($questions_to_surveys) > 0) {
                    $data['questions_to_surveys'] = $questions_to_surveys;
                }
            }
        }

        $lesson_conditions = eF_getTableData("lesson_conditions", "*", "lessons_ID=".$this -> lesson['id']);
        if (sizeof($lesson_conditions) > 0) {
            $data['lesson_conditions'] = $lesson_conditions;
        }

        $projects = eF_getTableData("projects", "*", "lessons_ID=".$this -> lesson['id']);
        if (sizeof($projects) > 0) {
            $data['projects'] = $projects;
        }

        $lesson_files = eF_getTableData("files", "*", "path like '".str_replace(G_ROOTPATH, '', EfrontDirectory :: normalize($this -> directory))."%'");
        if (sizeof($lesson_files) > 0) {
            $data['files'] = $lesson_files;
        }

        // MODULES - Export module data
        // Get all modules (NOT only the ones that have to do with the user type)
        $modules = eF_loadAllModules();
        foreach ($modules as $module) {
            if ($moduleData = $module -> onExportLesson($this -> lesson['id'])) {
                $data[$module -> className] = $moduleData;
            }
        }

        file_put_contents($this -> directory.'/'."data.dat", serialize($data));                         //Create database dump file
        $lessonDirectory = new EfrontDirectory($this -> directory);
        $file            = $lessonDirectory -> compress($this -> lesson['id'].'_exported.zip', false);  //Compress the lesson files
		$newList         = FileSystemTree :: importFiles($file['path']);                                //Import the file to the database, so we can download it
        $file            = new EfrontFile(current($newList));

 		$userTempDir     = $GLOBALS['currentUser'] -> user['directory'].'/temp';                        //The compressed file will be moved to the user's temp directory

        if (!is_dir($userTempDir)) {                                                                    //If the user's temp directory does not exist, create it
            $userTempDir = EfrontDirectory :: createDirectory($userTempDir, false);
            $userTempDir = $userTempDir['path'];
        }

        try {
            $existingFile = new EfrontFile($userTempDir.'/'.$this -> lesson['name'].'.zip');            //Delete any previous exported files
            $existingFile -> delete();
        } catch (Exception $e) {}

        $file -> rename($userTempDir.'/'.EfrontFile :: encode($this -> lesson['name']).'.zip', true);
        unlink($this -> directory.'/'."data.dat");                                                      //Delete database dump file

        return $file;
    }

    /**
     * Get system lessons
     *
     * This function is used used to return a list with all the system
     * lessons.
     * <br/>Example:
     * <code>
     * $lessons = EFrontLesson :: getLessons();
     * </code>
     *
     * @return array The lessons list
     * @since 3.5.0
     * @access public
     * @static
     */
    public static function getLessons() {
        $result = eF_getTableData("lessons l, directions d", "l.*, d.name as direction_name", "l.directions_ID=d.id");
        foreach ($result as $value) {
            $value['info']    = unserialize($value['info']);
            $lessons[$value['id']] = $value;
        }
        return $lessons;
    }

    /**
     * Get options
     *
     * This function is used to get the lesson specified options
     * <br/>Example:
     * <code>
     * $options = array('theory', 'tests');
     * $lesson -> getOptions($options);             //Get the values of 'theory' and 'tests' options
     * $lesson -> getOptions();                     //Get all options
     * </code>
     *
     * @param array $options An array of lesson options
     * @return array The values of the requested options
     * @since 3.5.0
     * @access public
     */
    public function getOptions($options) {
        if ($options && !is_array($options)) {
            $options = array($options);
        }

        if (sizeof($options) > 0) {
            $requestedOptions = array();
            foreach ($options as $value) {
                if (isset($this -> options[$value])) {
                    $requestedOptions[$value] = $this -> options[$value];
                }
            }
            return $requestedOptions;
        } else {
            return $this -> options;
        }

    }

    /**
     * Set options
     *
     * This function sets the lesson options, based on the array
     * specified
     * <br/>Example:
     * <code>
     * $options = array('theory' => 1, 'tests' => 0);
     * $lesson -> setOptions($options);
     * </code>
     *
     * @parm array $options An array of lesson options
     * @since 3.5.0
     * @access public
     */
    public function setOptions($options) {
        foreach ($options as $key => $value) {
            if (isset($this -> options[$key])) {
                $this -> options[$key] = $value;
            }
        }
        $this -> lesson['options'] = serialize($this -> options);
        eF_updateTableData("lessons", array("options" => $this -> lesson['options']), "id=".$this -> lesson['id']);
    }

    /**
     * Store database values
     *
     * This function is used to store changed lesson properties
     * to the database.
     * <br/>Example:
     * <code>
     * $lesson = new EfrontLesson(4);           //Instantiate lesson with id 4
     * $lesson -> lesson['name'] = 'new name';  //Change a lesson's property, for example its name
     * $lesson -> persist();                    //Store any changed values to the database
     * </code>
     *
     * @since 3.5.0
     * @access public
     */
    public function persist() {
        $fields = array('name'            => $this -> lesson['name'],
                        'directions_ID'   => $this -> lesson['directions_ID'],
                        'info'            => $this -> lesson['info'],
                        'price'           => $this -> lesson['price'],
                        'active'          => $this -> lesson['active'],
                        'options'         => serialize($this -> options),
                        'languages_NAME'  => $this -> lesson['languages_NAME'],
                        'metadata'        => $this -> lesson['metadata'],
                        'course_only'     => $this -> lesson['course_only'],
                        'certificate'     => $this -> lesson['certificate'],
//                        'auto_certificate'=> $this -> lesson['auto_certificate'],
//                        'auto_complete'   => $this -> lesson['auto_complete'],
//                        'publish'         => $this -> lesson['publish'],
                        'from_timestamp'  => $this -> lesson['from_timestamp'],
                        'to_timestamp'    => $this -> lesson['to_timestamp'],
                        'shift'           => $this -> lesson['shift']);

        if (!eF_updateTableData("lessons", $fields, "id=".$this -> lesson['id'])) {
            throw new EfrontUserException(_DATABASEERROR, EfrontUserException :: DATABASE_ERROR);
        }

        EfrontSearch :: removeText('lessons', $this -> lesson['id'], 'title');                                      //Refresh the search keywords
        EfrontSearch :: insertText($fields['name'], $this -> lesson['id'], "lessons", "title");
    }

    /**
     * Revoke sertificate
     *
     * This function is used to revoke the certificate for the
     * specified user.
     * <br/>Example:
     * <code>
     * $lesson -> revokeCertificate($login);
     * </code>
     *
     * @param string $login The user to revoke certificate for
     * @return boolean Whether the certificate was revoked successfully
     * @since 3.5.0
     * @accee
     */
    public function revokeCertificate($login) {
        if (eF_checkParameter($login, 'login')) {
            eF_updateTableData("users_to_lessons", array("issued_certificate" => ""), "users_LOGIN='$login' and lessons_ID=".$this -> lesson['id']);
            return true;
        } else {
            throw new EfrontUserException(_INVALIDLOGIN.': '.$login, EfrontUserException :: INVALID_LOGIN);
        }
    }

    /**
     * Issue certificate for the specified user
     * This function is used to issue a certificate for
     * the specified user.
     * <br/>Example:
     * <code>
     * $certificate = $lesson -> prepareCertificate('jdoe');            //Prepare the certificate for user 'jdoe'
     * $lesson -> issueCertificate('jdoe', $certificate);               //Issue certificate for user 'jdoe'
     * </code>
     *
     * @param string $login The login of the user to issue certificate for
     * @return boolean true if the certificate was issued successfully
     * @since 3.5.0
     * @access public
     */
    public function issueCertificate($login, $certificate) {
        if (eF_checkParameter($login, 'login')) {
            eF_updateTableData("users_to_lessons", array("issued_certificate" => $certificate), "users_LOGIN='$login' and lessons_ID=".$this -> lesson['id']);
            return true;
        } else {
            throw new EfrontUserException(_INVALIDLOGIN.': '.$login, EfrontUserException :: INVALID_LOGIN);
        }
    }

    /**
     * Prepare certificate for user
     *
     * This function is used to prepare the certificate that
     * will be issued to the specified user. It inserts user data
     * at the appropriate positions inside the certificate string
     * <br/>Example:
     * <code>
     * $certificate = $lesson -> prepareCertificate('jdoe');
     * </code>
     *
     * @param string $login The user to prepare a certificate for
     * @return string The certificate
     * @since 3.5.0
     * @access public
     */
    public function prepareCertificate($login) {
        if (eF_checkParameter($login, 'login')) {
            $certificate = $this -> getCertificate();
            $lessonUser  = EfrontUserFactory :: factory($login);
            $userStats   = EfrontStats::getStudentsLessonStatus($this, $login);

            $patterns     = array('/#user_name#/', '/#user_surname#/','/#lesson_name#/', '/#grade#/', '/#date#/');
            $replacements = array($lessonUser -> user['name'], $lessonUser -> user['surname'], $this -> lesson['name'], $userStats[$login]['score'], '#filter:timestamp-'.time()."#");

            $certificate  = preg_replace($patterns, $replacements, $certificate);

            return $certificate;
        } else {
            throw new EfrontUserException(_INVALIDLOGIN.': '.$login, EfrontUserException :: INVALID_LOGIN);
        }
    }

    /**
     * Get the lessoncertificate
     *
     * This function is used to retrieve the certificate template
     * used in the lesson
     * <br/>Example:
     * <code>
     * $lesson -> getCertificate();                             //Retuns the lesson certificate template
     * </code>
     *
     * @return string The lesson certificate
     * @since 3.5.0
     * @access public
     */
    public function getCertificate() {
        if (!$this -> lesson['certificate'] && is_file(G_SMARTYPATH."certificate-".$this -> lesson['languages_NAME'].".tpl")) {
            $certificate = file_get_contents(G_SMARTYPATH."certificate-".$this -> lesson['languages_NAME'].".tpl");
        } elseif ($this -> lesson['certificate']) {
            $certificate = $this -> lesson['certificate'];
        } else {
            $certificate = _DEFAULTCERTIFICATE;
        }

        return $certificate;
    }

    /**
     * Set the lesson certificate
     *
     * This function is used to set the lesson certificate
     * template.
     * <br/>Example:
     * <code>
     * $lesson -> setCertificate($certificate);
     * </code>
     *
     * @param string $certificate The lesson certificate template
     * @since 3.5.0
     * @access public
     * @todo check parameter
     */
    public function setCertificate($certificate) {
        eF_updateTableData("lessons", array("certificate" => $certificate), "id=".$this -> lesson['id']);
    }

    /**
     * Get lesson conditions
     *
     * This function can be used to retrieve the conditions set
     * for the current lesson
     * <br/>Example:
     * <code>
     * $lesson -> getConditions();                  //Returns an array with the lesson conditions
     * </code>
     *
     * @return array The lesson conditions
     * @since 3.5.0
     * @access public
     */
    public function getConditions() {
        if (!$this -> conditions) {
            $conditions = eF_getTableData("lesson_conditions", "*", "lessons_ID=".$this -> lesson['id']);
            $this -> conditions = array();
            foreach ($conditions as $value) {
                $value['options'] = unserialize($value['options']);
                $this -> conditions[$value['id']] = $value;
            }
        }

        return $this -> conditions;
    }

    /**
     * Delete lesson conditions
     *
     * This function is used to delete one or more lesson conditions
     * <br/>Example:
     * <code>
     * $lesson -> deleteConditions(3);                                  //Delete condition with id 3
     * $lesson -> deleteConditions(array(3, 6, 34));                    //Delete conditions with ids 3,6 and 34
     * </code>
     *
     * @param mixed $conditions An id or an array of ids
     * @return array The remaining conditions
     * @since 3.5.0
     * @access public
     */
    public function deleteConditions($conditions) {
        if ($this -> conditions === false) {                            //Initialize conditions, if you haven't done so
            $this -> getConditions();
        }
        if (!is_array($conditions)) {                                    //Convert single condition to array
            $conditions = array($conditions);
        }
        foreach ($conditions as $conditionId) {
            if (eF_checkParameter($conditionId, 'id') && in_array($conditionId, array_keys($this -> conditions))) {
                eF_deleteTableData("lesson_conditions", "id=$conditionId");
                unset($this -> rules[$conditionId]);
            }
        }
        return $this -> conditions;
    }

    /**
     * Get lesson projects
     *
     * This function is usd to retrieve the projects of this lesson
     * <br/>Example:
     * <code>
     * $lesson = new EfrontLesson(65);                          //Create new lesson object
     * $projectList = $lesson -> getProjects();                 //Get all projects for this lesson
     * $projectList = $lesson -> getProjects(true);             //Get all projects for this lesson as an EfrontProject objects list
     * $projectList = $lesson -> getProjects(true, 'jdoe');     //Get projects assigned to 'jdoe' for this lesson, as an EfrontProject objects list
     * </code>
     *
     * @param boolean $returnObjects Whether to return EfrontProject objects or just an array with projects properties
     * @param string $login If specified, return projects only assigned to this user
     * @return array an array of lesson projects
     * @since 3.5.0
     * @access public
     */
    public function getProjects($returnObjects = false, $login = false, $nonExpired = false) {
        if ($login && eF_checkParameter($login, 'login')) {
            !$nonExpired ? $result = eF_getTableData("projects p, users_to_projects up", "p.*, up.grade, up.comments, up.filename", "up.users_LOGIN = '$login' and up.projects_ID = p.id and p.lessons_ID=".$this -> lesson['id']) : $result = eF_getTableData("projects p, users_to_projects up", "p.*, up.grade, up.comments, up.filename", "p.deadline > ".time()." and up.users_LOGIN = '$login' and up.projects_ID = p.id and p.lessons_ID=".$this -> lesson['id']);
        } else {
            !$nonExpired ? $result = eF_getTableData("projects", "*", "lessons_ID=".$this -> lesson['id']) : $result = eF_getTableData("projects", "*", "p.deadline > ".time()." and lessons_ID=".$this -> lesson['id']);
        }
        $projects = array();
        foreach ($result as $value) {
            $returnObjects ? $projects[$value['id']] = new EfrontProject($value['id']) : $projects[$value['id']] = $value;
        }

        return $projects;
    }

    /**
     * Print a link with tooltip
     *
     * This function is used to print a lesson link with a popup tooltip
     * containing information on this lesson. The link must be provided
     * and optionally the information.
     * <br/>Example:
     * <code>
     * echo $lesson -> toHTMLTooltipLink('student.php?ctg=control_panel&lessons_ID=2');
     * </code>
     *
     * @param string $link The link to print
     * @param array $lessonInformation The information to display (According to the EfrontLesson :: getInformation() format)
     * @since 3.5.0
     * @access public
     */
    public function toHTMLTooltipLink($link, $lessonInformation = false) {
        if (!$lessonInformation) {
            $lessonInformation = $this -> getInformation();
        }

        sizeof($lessonInformation['content']) > 0 || sizeof($lessonInformation['tests']) > 0 ? $classes[] = 'nonEmptyLesson' : $classes[] = 'emptyLesson';     //Display the link differently depending on whether it has content or not
        if (!$link) {
            $link      = 'javascript:void(0)';
            $classes[] = 'inactiveLink';
        }

        if ($lessonInformation['professors']) {
            foreach ($lessonInformation['professors'] as $value) {
                $professorsString[] = $value['name'].' '.$value['surname'];
            }
            $lessonInformation['professors'] = implode(", ", $professorsString);
        }
        foreach ($lessonInformation as $key => $value) {
            if ($value) {
                switch ($key) {
                    case 'professors'         : $tooltipInfo[] = '<strong>'._PROFESSORS."</strong>: $value<br/>";         break;
                    case 'content'            : $tooltipInfo[] = '<strong>'._CONTENTUNITS."</strong>: $value<br/>";       break;
                    case 'tests'              : $tooltipInfo[] = '<strong>'._TESTS."</strong>: $value<br/>";              break;
                    case 'projects'           : $tooltipInfo[] = '<strong>'._PROJECTS."</strong>: $value<br/>";           break;
                    case 'course_dependency'  : $tooltipInfo[] = '<strong>'._DEPENDSON."</strong>: $value<br/>";          break;
                    case 'from_timestamp'     : $tooltipInfo[] = '<strong>'._AVAILABLEFROM."</strong>: ".formatTimestamp($value, 'time_nosec')."<br/>";break;
                    case 'to_timestamp'       : $tooltipInfo[] = '<strong>'._AVAILABLEUNTIL."</strong>: ".formatTimestamp($value, 'time_nosec')."<br/>"; break;
                    case 'general_description': $tooltipInfo[] = '<strong>'._GENERALDESCRIPTION."</strong>: $value<br/>"; break;
                    case 'assessment'         : $tooltipInfo[] = '<strong>'._ASSESSMENT."</strong>: $value<br/>";         break;
                    case 'objectives'         : $tooltipInfo[] = '<strong>'._OBJECTIVES."</strong>: $value<br/>";         break;
                    case 'lesson_topics'      : $tooltipInfo[] = '<strong>'._LESSONTOPICS."</strong>: $value<br/>";       break;
                    case 'resources'          : $tooltipInfo[] = '<strong>'._RESOURCES."</strong>: $value<br/>";          break;
                    case 'other_info'         : $tooltipInfo[] = '<strong>'._OTHERINFO."</strong>: $value<br/>";          break;
                    default: break;
                }
            }
        }
        if (sizeof($tooltipInfo) > 0) {
            $classes[]     = 'info';
            $tooltipString = '
                <a href = "'.$link.'" class = "'.implode(" ", $classes).'" style = "vertical-align:middle;">
                    '.$this -> lesson['name'].'
                    <img class = "tooltip" border = "0" src="images/others/tooltip_arrow.gif"/><span class = "tooltipSpan">
                    '.implode("", $tooltipInfo).'</span></a>';
        } else {
            $tooltipString = '
                <a href = "'.$link.'" class = "'.implode(" ", $classes).'" style = "vertical-align:middle;">
                    '.$this -> lesson['name'].'</a>';
        }
        return $tooltipString;
    }



   /**
     * Get all skills: for the skills this lesson offers the lesson_ID value will be filled
     *
     * <br/>Example:
     * <code>
     * $skillsOffered = $lesson -> getSkills();
     * </code>
     *
     * @return an array with skills where each record has the form [skill_ID] => [lesson_ID, description, specification,skill_ID]
     * @since 3.5.0
     * @access public
     */
    public function getSkills() {
        if (! $this -> skills) {
            $skills = eF_getTableData("module_hcd_skills LEFT OUTER JOIN module_hcd_lesson_offers_skill ON (module_hcd_lesson_offers_skill.skill_ID = module_hcd_skills.skill_ID AND module_hcd_lesson_offers_skill.lesson_ID='".$this -> lesson['id']."')", "description,specification, module_hcd_skills.skill_ID,lesson_ID","");
            foreach ($skills as $skill) {
                $skID = $skill['skill_ID'];
                $this -> skills[$skID] = $skill;
            }
        }
        return $this->skills;
    }



   /**
     * Assign a skill to this lesson or update an existing skill description
     *
     * This function is used to correlate a skill to the lesson - if the
     * lesson is completed then this skill is assigned to the user that completed it
     *
     * <br/>Example:
     * <code>
     * $lesson -> assignSkill(2, "Beginner PHP knowledge");   // The lesson will offer skill with id 2 and "Beginner PHP knowledge"
     * </code>
     *
     * @param $skill_ID the id of the skill to be assigned
     * @return boolean true/false
     * @since 3.5.0
     * @access public
     */
    public function assignSkill($skill_ID, $specification) {

        $this -> getSkills();

        // Check if the skill is not assigned as offered by this lesson
        if ($this -> skills[$skill_ID]['lesson_ID'] == "") {
            if ($ok = eF_insertTableData("module_hcd_lesson_offers_skill", array("skill_ID" => $skill_ID, "lesson_ID" => $this -> lesson['id'], "specification" => $specification))) {
                $this -> skills[$skill_ID]['lesson_ID'] = $this -> lesson['id'];
                $this -> skills[$skill_ID]['specification'] = $specification;
            } else {
                throw new EfrontLessonException(_EMPLOYEESRECORDCOULDNOTBEUPDATED, EfrontLessonException :: DATABASE_ERROR);
            }
        } else {
            if ($ok = eF_updateTableData("module_hcd_lesson_offers_skill", array("specification" => $specification), "skill_ID = '".$skill_ID."' AND lesson_ID = '". $this -> lesson['id'] ."'") ) {
                $this -> skills[$skill_ID]['specification'] = $specification;
            } else {
                throw new EfrontLessonException(_EMPLOYEESRECORDCOULDNOTBEUPDATED, EfrontLessonException :: DATABASE_ERROR);
            }
        }

        return true;
    }

   /**
     * Remove a skill that is offered from this lesson
     *
     * This function is used to stop the correlation of a skill to the lesson - if the
     * lesson is completed then this skill is assigned to the user that completed it
     *
     * <br/>Example:
     * <code>
     * $lesson -> removeSkill(2);   // The lesson will stop offering skill with id 2
     * </code>
     *
     * @param $skill_ID the id of the skill to be removed from the skills to be offered list
     * @return boolean true/false
     * @since 3.5.0
     * @access public
     */
    public function removeSkill($skill_ID) {

        $this -> getSkills();

        // Check if the skill is not assigned as offered by this lesson
        if ($this -> skills[$skill_ID]['lesson_ID'] == $this -> lesson['id']) {
            if ($ok = eF_deleteTableData("module_hcd_lesson_offers_skill", "skill_ID = '".$skill_ID."' AND lesson_ID = '". $this -> lesson['id'] ."'") ) {
                $this -> skills[$skill_ID]['specification'] = "";
                $this -> skills[$skill_ID]['lesson_ID'] = "";
            } else {
                throw new EfrontLessonException(_EMPLOYEESRECORDCOULDNOTBEUPDATED, EfrontLessonException :: DATABASE_ERROR);
            }
        }

        return true;
    }

}






?>