<?php

/**
 * CodeIgniter library
 *
 * @category CodeIgniter
 * @license /_licenses/untermStrich/agb_normal.pdf
 * @author Christian Wengg
 * @copyright 2009 untermStrich
 * @package us_libraries
 * @version $Id$
 */
if (!defined('BASEPATH')) { exit('No direct script access allowed'); }

if (!defined('BASEPATH')) { exit('No direct script access allowed'); }

require_once APPPATH . 'us_libraries/Value_object_addi.php';
require_once APPPATH . 'us_libraries/vendor/autoload.php';

/**
 * Used to save an project
 *
 * @property    My_Controller           $CI                     The main CI object
 */
class Project_values extends Value_object_addi {

    protected $old_id;
    protected $project_name;
    protected $project_number;
    protected $location;
    protected $purpose;
    protected $photo_file;
    protected $project_category_id;
    protected $start_date;
    protected $end_date;
    protected $project_manager_id;
    protected $division_manager_id;
    protected $client_id;
    protected $office_in_charge_id;
    protected $project_phase_id;
    protected $project_archive_id;
    protected $safekeeping_period;
    protected $measurement_value;
    protected $measurement_id;
    protected $is_add_to_indirect_costs;
    protected $is_private_project;
    protected $ignore_required_purpose;
    protected $work_area_category_id;
    protected $default_extras;
    protected $default_discount;
    protected $default_discount_days;
    protected $path_correspondence;
    protected $sync_correspondence;
    protected $path_inbox;
    protected $sync_inbox;
    protected $path_outbox;
    protected $sync_outbox;
    protected $path_drawings;
    protected $work_package_preset_id;
    protected $work_package_preset_chk_box;
    protected $flink2go_create;
    protected $realview_create;
    protected $dokspace_url_create;
    protected $projectadmin_create_dir; //Create the dirs on save
    protected $current_project_object; //The current project - used on update
    protected $orig_translated_structure_tree_root_node_cleaned;
    protected $path_correspondence_cleaned;
    protected $path_inbox_cleaned;
    protected $path_outbox_cleaned;
    protected $path_drawings_cleaned;
    protected $structure_id;
    protected $structure_tree_root_node;
    protected $orig_structure_tree_root_node; //Just insert on add
    protected $orig_translated_structure_tree_root_node; //Just insert on add
    protected $tree = array();

    protected $use_rel_paths_with_main_path;

    /**
     * Init the project values from $_POST
     *
     * @return  object  An Project_values object with all values out of the post array
     */
    public static function init_from_post() {
        $obj = new Project_values();
        $obj->CI = CI_Controller::get_instance();
        $obj->current_project_object = null;
        $obj->add_or_id = $obj->CI->input->post('projectadmin_edit');
        $obj->old_id = intval($obj->CI->input->post('projectadmin_old_id'));
        $obj->project_name = $obj->CI->input->post('projectadmin_project_name');
        $obj->project_number = $obj->CI->input->post('projectadmin_project_number');
        $obj->location = $obj->CI->input->post('projectadmin_location');
        $obj->purpose = $obj->CI->input->post('projectadmin_purpose');
        $obj->photo_file = $obj->CI->input->post('projectadmin_photo_file');
        $obj->project_category_id = $obj->CI->input->post('projectadmin_project_category');
        $obj->start_date = new UsDate($obj->CI->input->post('projectadmin_start_date'), null, true, null);
        $obj->end_date = new UsDate($obj->CI->input->post('projectadmin_end_date'), null, true, null);
        $obj->project_manager_id = $obj->CI->input->post('projectadmin_project_manager');
        $obj->division_manager_id = $obj->CI->input->post('projectadmin_division_manager');
        $obj->client_id = $obj->CI->input->post('projectadmin_client');
        $obj->office_in_charge_id = $obj->CI->input->post('projectadmin_office_in_charge');
        $obj->project_phase_id = $obj->CI->input->post('projectadmin_project_phase');
        $obj->project_archive_id = $obj->CI->input->post('projectadmin_project_archive');
        $obj->safekeeping_period = new UsDate($obj->CI->input->post('projectadmin_safekeeping_period'), null, true, null);
        $obj->measurement_value = $obj->CI->input->post('projectadmin_measurement_value');
        $obj->measurement_id = $obj->CI->input->post('projectadmin_measurement');
        $obj->is_add_to_indirect_costs = $obj->CI->input->post('projectadmin_is_add_to_indirect_costs') ? true : false;
        $obj->is_private_project = $obj->CI->input->post('projectadmin_is_private_project') ? true : false;
        $obj->ignore_required_purpose = $obj->CI->input->post('projectadmin_ignore_required_purpose') ? true : false;
        $obj->work_area_category_id = $obj->CI->input->post('projectadmin_work_area_category');
        $obj->work_package_preset_id = $obj->CI->input->post('projectadmin_work_package_preset');
        $obj->work_package_preset_chk_box = $obj->CI->input->post('projectadmin_show_work_package_preset')==='TRUE' ? true : false;

        $obj->default_extras = usnumber_to_float($obj->CI->input->post('projectadmin_default_extras'));
        $obj->default_discount = usnumber_to_float($obj->CI->input->post('projectadmin_default_discount'));
        $obj->default_discount_days = intval($obj->CI->input->post('projectadmin_default_discount_days'));
        
        $obj->flink2go_create = intval($obj->CI->input->post('projectadmin_flink2go_create'));
        $obj->realview_create = intval($obj->CI->input->post('projectadmin_realview_create'));
        $obj->dokspace_url_create = intval($obj->CI->input->post('projectadmin_dokspace_url_create'));

        $obj->path_correspondence = trim($obj->CI->input->post('projectadmin_path_correspondence'));
        $obj->sync_correspondence = false;
        $obj->path_inbox = trim($obj->CI->input->post('projectadmin_path_inbox'));
        $obj->sync_inbox = false;
        $obj->path_outbox = trim($obj->CI->input->post('projectadmin_path_outbox'));
        $obj->sync_outbox = false;
        $obj->path_drawings = trim($obj->CI->input->post('projectadmin_path_drawings'));
        $obj->projectadmin_create_dir = $obj->CI->input->post('projectadmin_create_dir') ? true : false;
        $obj->addi_vars = $obj->CI->projects->get_addi_vars_post();
        $obj->use_rel_paths_with_main_path = ($obj->CI->input->post('projectadmin_use_rel_paths_with_main_path') === 'true') ? true : false;

        $obj->orig_translated_structure_tree_root_node = $obj->CI->input->post('projectadmin_path_main');
        if (!empty($obj->orig_translated_structure_tree_root_node)) {
            $obj->orig_translated_structure_tree_root_node = self::clean_path($obj->orig_translated_structure_tree_root_node);
        }

        $obj->structure_id = intval($obj->CI->input->post('projectadmin_structure'));
        $obj->structure_tree_root_node = self::clean_path($obj->CI->input->post('projectadmin_structure_tree_root_node'));

        self::prepare_structure_vars($obj);

        self::restrictions_for_SaaSV2($obj);
        return $obj;
    }

    /**
     * create new project object from upload values
     *
     * @param $values   object  Imported values
     * @return object   New project_values_object
     */
    public static function init_from_values($values) {

        $obj = new Project_values();
        $obj->CI = CI_Controller::get_instance();
        $obj->CI->load->model('projects_model', 'projects', true);
        $obj->CI->load->model('addresses_model', 'addresses', true);
        $obj->CI->load->model("work_packages_presets_model", "presets", true);
        $obj->CI->load->model("project_phases_model", "phases", true);
        $obj->CI->load->model("staff_model", "staff", true);

        $obj->current_project_object = null;
        $obj->add_or_id = $values->add_or_id;
        $obj->project_name = $values->project_name;
        $obj->project_number = $values->project_number ?? '';
        $obj->location = $values->location ?? '';
        $obj->photo_file = isset($values->photo_file) ? $values->photo_file : null;
        if (isset($values->purpose)) {
            $obj->purpose = $values->purpose;
        } elseif (strtolower($obj->add_or_id) === 'add') {
            $obj->purpose = '';
        }
        $obj->project_manager_id = $values->project_manager_id;
        $obj->division_manager_id = isset($values->division_manager_id) ? $values->division_manager_id : null;
        if (isset($values->client_id)) {
            $obj->client_id = $values->client_id;
        }
        if (isset($values->office_in_charge_id)) {
            $obj->office_in_charge_id = $values->office_in_charge_id;
        }
        if (isset($values->project_phase_id)) {
            $obj->project_phase_id = $values->project_phase_id;
        }
        $obj->project_archive_id = isset($values->project_archive_id) ? $values->project_archive_id : null;
        $obj->measurement_value = isset($values->measurement_value) ? $values->measurement_value : null;
        $obj->measurement_id = isset($values->measurement_id) ? $values->measurement_id : null;
        $obj->is_add_to_indirect_costs = boolval($values->is_add_to_indirect_costs ?? false);
        $obj->is_private_project = boolval($values->is_private_project ?? false);
        $obj->ignore_required_purpose = isset($values->ignore_required_purpose) ? boolval($values->ignore_required_purpose) : false;
        $obj->work_area_category_id = isset($values->work_area_category_id) ? intval($values->work_area_category_id) : null;
        if (strtolower($obj->add_or_id) === 'add') {
            $obj->work_package_preset_id = $values->work_package_preset_id;

            if (!is_numeric($obj->work_package_preset_id)) {
                $obj->fetch_work_package_preset_id_by_name();
            }
        }

        if (isset($values->start_date)) {
            $start_date = is_object($values->start_date) ? $values->start_date : new UsDate($obj->fixDateFormat($values->start_date));
        } else {
            $start_date = new UsDate('');
        }
        if (isset($values->end_date)) {
            $end_date = is_object($values->end_date) ? $values->end_date : new UsDate($obj->fixDateFormat($values->end_date));
        } else {
            $end_date = new UsDate('');
        }
        $obj->start_date = $start_date;
        $obj->end_date = $end_date;

        if (isset($values->default_extras)) {
            $obj->default_extras = floatval($values->default_extras);
        }
        if (isset($values->default_discount)) {
            $obj->default_discount = floatval($values->default_discount);
        }
        if (isset($values->default_discount_days)) {
            $obj->default_discount_days = intval($values->default_discount_days);
        }
        if (isset($values->safekeeping_period)) {
            $obj->safekeeping_period = ($values->safekeeping_period instanceof UsBasicDateTime) ? $values->safekeeping_period : $obj->fixSafekeepingPeriod($values->safekeeping_period);
        } elseif (strtolower($obj->add_or_id) === 'add') {
            $obj->safekeeping_period = new UsDate(null);
        }
        if (isset($values->project_category_id)) {
            $obj->project_category_id = intval($values->project_category_id);
        } elseif (isset($values->project_category_name)) {
            $obj->project_category_id = $obj->CI->projects->get_category_sort($values->project_category_name);
        }

        $obj->project_number = $values->project_number;
        $obj->project_name = $values->project_name;

        if (!is_numeric($obj->project_phase_id)) {
            $obj->findProjectPhaseId();
        }

        if (!is_numeric($obj->client_id)) {
            $obj->findClient();
        }

        if (!is_numeric($obj->project_manager_id)) {
            $obj->findStaff($obj->project_manager_name, $obj->project_manager_id);
        }

        if (!is_numeric($obj->division_manager_id)) {
            $obj->findStaff($obj->division_manager_name, $obj->division_manager_id);
        }

        if (!is_numeric($obj->office_in_charge_id)) {
            $obj->findStaff($obj->office_in_charge_name, $obj->office_in_charge_id);
        }

        $obj->projectadmin_create_dir = isset($values->create_dir) ? boolval($values->create_dir) : false;

        $obj->path_correspondence = isset($values->path_correspondence) ? self::clean_path($values->path_correspondence) : '';
        $obj->sync_correspondence = isset($values->sync_correspondence) ? boolval($values->sync_correspondence) : false;
        $obj->path_inbox = isset($values->path_inbox) ? self::clean_path($values->path_inbox) : '';
        $obj->sync_inbox = isset($values->sync_inbox) ? boolval($values->sync_inbox) : false;
        $obj->path_outbox = isset($values->path_outbox) ? self::clean_path($values->path_outbox) : '';
        $obj->sync_outbox = isset($values->sync_outbox) ? boolval($values->sync_outbox) : false;
        $obj->path_drawings = isset($values->path_drawings) ? self::clean_path($values->path_drawings) : '';
        $obj->path_drawings_inbox = isset($values->path_drawings_inbox) ? self::clean_path($values->path_drawings_inbox) : '';

       $obj->structure_tree_root_node = isset($values->projectadmin_structure_tree_root_node) ? self::clean_path($values->projectadmin_structure_tree_root_node) : null;

       $obj->orig_translated_structure_tree_root_node = isset($values->projectadmin_path_main) ? $values->projectadmin_path_main : null;
       if (!empty($obj->orig_translated_structure_tree_root_node)) {
           $obj->orig_translated_structure_tree_root_node = self::clean_path($obj->orig_translated_structure_tree_root_node);
       }

        $obj->structure_id = isset($values->structure_id) ? intval($values->structure_id) : 0;
        $obj->structure_tree_root_node = isset($values->structure_tree_root_node) ? self::clean_path($values->structure_tree_root_node) : '';

        self::prepare_structure_vars($obj);

        if (!isset($values->addi_fields)) {
            $values->addi_fields = $obj->CI->projects->get_addi_list();
        }
        self::init_addi_vars_from_values($obj, $values);

        self::restrictions_for_SaaSV2($obj);
        return $obj;
    }

    /**
     * just fix the excel date format
     *
     * @param $excelDate    Date as it's imported
     * @return string       Formatted date value
     */
    private function fixDateFormat($excelDate) {

        $result = \PhpOffice\PhpSpreadsheet\Style\NumberFormat::toFormattedString($excelDate, 'YYYY-MM-DD HH:MM:SS');

        return $result;
    }

    /**
     * checks addresses to get client id by name
     */
    private function findClient() {

        $this->client_name = $this->client_id;
        $cleanName = self::cleanAddressName($this->client_id);

        $reqVars = new stdClass();
        $reqVars->keyword = $cleanName;
        $list = $this->CI->addresses->get_list($reqVars);

        foreach ($list as $item) {
            if (strtolower($this->client_name ??'') === strtolower($item->name ??'')) {
                $this->client_id = $item->id;
                return;
                
            }
        }

        $this->client_id = null;
    }

    /**
     * translates name to id for every staff field
     *
     * @param String (reference)    $name  Reference of the imported name
     * @param mixed (reference)     $id    Reference of the id, may contain the name at first
     */
    private function findStaff(&$name, &$id) {

        $name = $id;
        $list = $this->CI->staff->get_list();

        foreach ($list as $item) {
            if (strtolower($name ??'') === strtolower($item->staff_name ??'')) {
                $id = $item->id;
                return;
            }
        }

        $name = null;
        $id = null;
    }

    /**
     * translate project phase name to id
     */
    private function findProjectPhaseId() {

        $phases = $this->CI->phases->get_list();

        foreach ($phases as $phase) {
            if (strtolower($this->project_phase_id ??'') === strtolower($phase->name ??'')) {
                $this->project_phase_id = $phase->id;
                return;
            }
        }

        $this->project_phase_id = 0;
    }

    /**
     * if no safekeeping period is set, set it to 10 years in the future
     *
     * @param mixed $date  uploaded safekeeping_period date
     * @return UsDate   valid date
     */
    private function fixSafekeepingPeriod($date) {

        if (intval($date) === 0)
            return new UsDate(date("Y-m-d", strtotime("+10 year")));
        else
            return new UsDate($this->fixDateFormat($date));
    }

    /**
     * Gets the work package preset id by its name
     */
    private function fetch_work_package_preset_id_by_name() {

        $presets = $this->CI->presets->get_tree_list();

        foreach ($presets as $preset) {
            if (strtolower($preset->tree_name ??'') === strtolower($this->work_package_preset_id ??'')) {
                $this->work_package_preset_id = $preset->tree_id;
                return;
            }
        }
        $this->work_package_preset_id = 1;
    }

    /**
     * uStrich export writes 'name, city' as client name,
     * so we fix this to get only the name
     *
     * @param $string   String  Client name as it's imported
     * @return String   Clean string (only name, without city)
     */
    private function cleanAddressName($string) {

        $pos = strpos($string ??'' , ',');
        if (!$pos)
            return $string;

        return substr($string ??'', 0, $pos);
    }

    /**
     * Clean the path
     *
     * @param   string  $path   Project path
     * @return  string  Cleaned
     */
    private static function clean_path($path) {
        if (trim(empty($path))){
            return $path;
        }

        if (substr($path, -1) != '/' && substr($path, -1) != '\\') {
            $path .= DIRECTORY_SEPARATOR;
        }

        if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
            $path = str_replace('\\', DIRECTORY_SEPARATOR, $path);
        }
        return $path;
    }

    /**
     * @param Project_values $obj
     * @return void
     * @throws Exception
     */
    public static function prepare_structure_vars(Project_values $obj): void
    {
        if (strtolower($obj->add_or_id) === 'add' && $obj->structure_id > 0) {
            $obj->CI->load->model('Project_directory_structure_tree_model', 'project_directory_structure_tree');
            $seperator = '/';
            if (strpos($obj->structure_tree_root_node, '\\') !== false) {
                $seperator = '\\';
            }
            $paths = $obj->CI->project_directory_structure_tree->get_paths_full_path($obj->structure_id, $seperator, false, $obj->structure_tree_root_node);
            $obj->path_correspondence = '';
            $obj->path_inbox = '';
            $obj->path_outbox = '';
            $obj->path_drawings = '';
            $obj->sync_correspondence = true;
            $obj->sync_inbox = true;
            $obj->sync_outbox = true;
            foreach ($paths as $type => $path) {
                $path_root = $obj->structure_tree_root_node;
                if (trim(str_replace('/', '\\', $obj->structure_tree_root_node)) == trim(str_replace('/', '\\', $path))) {
                    $path = '';
                } elseif ($obj->CI->load->filesystem($path) instanceof O365_filesystem_creator) {
                    $path = trim($path, '/');
                    $path_root = '';
                }
                switch ($type) {
                    case Project_directory_structure_tree_model::PATH_CORRESPONDENCE:
                        $obj->path_correspondence = $path_root . $path;
                        break;
                    case Project_directory_structure_tree_model::PATH_INBOX:
                        $obj->path_inbox = $path_root . $path;
                        break;
                    case Project_directory_structure_tree_model::PATH_OUTBOX:
                        $obj->path_outbox = $path_root . $path;
                        break;
                    case Project_directory_structure_tree_model::PATH_DRAWINGS:
                        $obj->path_drawings = $path_root . $path;
                        break;
                    default:
                        break;
                }
            }

            $obj->tree = $obj->CI->project_directory_structure_tree->get_tree_list($obj->structure_id);
            if (!is_array($obj->tree)) {
                basic_error($obj->tree, null, __CLASS__ . '::' . __FUNCTION__);
            }

            $obj->orig_structure_tree_root_node = $obj->structure_tree_root_node;
            $obj->orig_translated_structure_tree_root_node = $obj->structure_tree_root_node;
        }

        $use_rel_paths_with_main_path = function(&$path) use ($obj) {
            if ($obj->isNew() && $obj->use_rel_paths_with_main_path === true) {
                $path = ltrim($path, './\\');
                $path = $obj->orig_translated_structure_tree_root_node . '' . $path;
            }
        };

        if (!empty($obj->path_correspondence)) {
            $use_rel_paths_with_main_path($obj->path_correspondence);
            $obj->path_correspondence = self::clean_path($obj->path_correspondence);
        }
        if (!empty($obj->path_inbox)) {
            $use_rel_paths_with_main_path($obj->path_inbox);
            $obj->path_inbox = self::clean_path($obj->path_inbox);
        }
        if (!empty($obj->path_outbox)) {
            $use_rel_paths_with_main_path($obj->path_outbox);
            $obj->path_outbox = self::clean_path($obj->path_outbox);
        }
        if (!empty($obj->path_drawings)) {
            $use_rel_paths_with_main_path($obj->path_drawings);
            $obj->path_drawings = self::clean_path($obj->path_drawings);
        }
    }

    /**
     * Restrictions for SaaS v2
     *
     * @param Project_values $obj
     * @return void
     * @throws Exception
     */
    public static function restrictions_for_SaaSV2(Project_values $obj): void
    {
        if ($obj->CI->config->item('us_rights_mode') >= 3) {
            $saas_paths = array();
            if (isset($obj->orig_structure_tree_root_node)) $saas_paths[] = $obj->orig_structure_tree_root_node;
            if (isset($obj->orig_translated_structure_tree_root_node)) $saas_paths[] = $obj->orig_translated_structure_tree_root_node;
            if (isset($obj->path_correspondence)) $saas_paths[] = $obj->path_correspondence;
            if (isset($obj->path_inbox)) $saas_paths[] = $obj->path_inbox;
            if (isset($obj->path_outbox)) $saas_paths[] = $obj->path_outbox;
            if (isset($obj->path_drawings)) $saas_paths[] = $obj->path_drawings;

            foreach ($saas_paths as $saas_path) {
                if (empty($saas_path)) continue;

                $path_object = $obj->CI->load->filesystem($saas_path);

                if (!($path_object instanceof O365_filesystem_creator)) {
                    basic_error($obj->CI->lang->linef('projectadmin_saas_no_O365_path', $saas_path), null, __CLASS__ . '::' . __FUNCTION__);
                }

                if (stripos($saas_path, '../') !== false) {
                    basic_error($obj->CI->lang->linef('projectadmin_dot_dot_slash_path', $saas_path), null, __CLASS__ . '::' . __FUNCTION__);
                }
            }
        }
    }

    /**
     * Update and clean all before save
     *
     * @return  void
     */
    public function update_and_clean_all_before_save() {
        $this->update_all_paths_from_values();
        $this->replace_folder_translation();
        if ($this->structure_id <= 0) {
            $this->clean_paths();
        }
    }

    /**
     * Validate and ensure all values are appropriate
     *
     * @return  mixed   false on success, else the error message
     */
    public function validate() {
        if ($this->add_or_id !== 'add' && !is_numeric($this->add_or_id)) {
            return 'Project ID has to be "add" or an ID';
        }

        if ($this->add_or_id === 'add' && !is_numeric($this->work_package_preset_id) && !$this->is_new_copy()) {
            return 'Work package ID has to be an ID';
        }

        return false;
    }
    
    public function get_manager_ids() {
        return array(
            'project_manager_id' => $this->project_manager_id,
            'division_manager_id' => $this->division_manager_id
        );
    }
    
    /**
     * Get infos for duplicate check (project_name, project_number)
     *
     * @return  array
     */
    public function get_for_duplicate_check() {
        $data = array(
            'project_name' => $this->project_name,
            'project_number' => $this->project_number,
        );

        if ($this->add_or_id !== 'add') {
            $data['id'] = intval($this->add_or_id);
        } else {
            $data['id'] = $this->add_or_id;
        }

        return $data;
    }

    /**
     * Get project to save
     * 
     * Always call set_current_project_object() before calling this methode
     *
     * @return  array
     */
    public function get_project_to_save() {
        $this->CI->load->library('upload');

        $data = array(
            'project_name' => $this->rem_newlines($this->project_name),
            'project_number' => $this->rem_newlines($this->project_number),
            'location' => $this->location,
            'purpose' => $this->purpose,
            'project_category_id' => intval($this->project_category_id),
            'start_date' => $this->start_date->mysql(),
            'end_date' => $this->end_date->mysql(),
            'project_manager_id' => intval($this->project_manager_id),
            'division_manager_id' => intval($this->division_manager_id),
            'client_id' => intval($this->client_id),
            'office_in_charge_id' => intval($this->office_in_charge_id),
            'project_phase_id' => intval($this->project_phase_id),
            'project_archive_id' => intval($this->project_archive_id),
            'safekeeping_period' => $this->safekeeping_period->mysql(),
            'measurement_value' => usnumber_to_float($this->measurement_value),
            'measurement_id' => intval($this->measurement_id),
            'is_add_to_indirect_costs' => $this->is_add_to_indirect_costs,
            'is_private_project' => $this->is_private_project,
            'ignore_required_purpose' => $this->ignore_required_purpose,
            'work_area_category_id' => intval($this->work_area_category_id),
            'sync_correspondence' => $this->sync_correspondence,
            'sync_inbox' => $this->sync_inbox,
            'sync_outbox' => $this->sync_outbox,
            'default_extras' => $this->default_extras ?? null,
            'default_discount' => $this->default_discount ?? null,
            'default_discount_days' => $this->default_discount_days ?? null,
        );

        if ($this->add_or_id === 'add' && $this->structure_id > 0) {//Just add this info on add
            $data['orig_structure_id'] = $this->structure_id;
            $data['orig_structure_tree_root_node'] = $this->orig_structure_tree_root_node;
        }
        if ($this->add_or_id === 'add') {
            $data['work_package_preset_id'] = intval($this->work_package_preset_id);
            $data['orig_translated_structure_tree_root_node'] = $this->orig_translated_structure_tree_root_node;
            $data['path_correspondence'] = $this->path_correspondence;
            $data['path_inbox'] = $this->path_inbox;
            $data['path_outbox'] = $this->path_outbox;
            $data['path_drawings'] = $this->path_drawings;
        } else {
            if (!isset($this->current_project_object)) {
                basic_error('Please use set_current_project_object() before calling get_project_to_save()', $mode, __CLASS__ . '::' . __FUNCTION__);
            }
            if ($this->current_project_object->orig_translated_structure_tree_root_node !== $this->orig_translated_structure_tree_root_node) {
                $data['orig_translated_structure_tree_root_node'] = $this->orig_translated_structure_tree_root_node;
            }
            if ($this->current_project_object->path_correspondence !== $this->path_correspondence) {
                $data['path_correspondence'] = $this->path_correspondence;
            }
            if ($this->current_project_object->path_inbox !== $this->path_inbox) {
                $data['path_inbox'] = $this->path_inbox;
            }
            if ($this->current_project_object->path_outbox !== $this->path_outbox) {
                $data['path_outbox'] = $this->path_outbox;
            }
            if ($this->current_project_object->path_drawings !== $this->path_drawings) {
                $data['path_drawings'] = $this->path_drawings;
            }
        }

        if ($this->photo_file !== false && !empty($this->photo_file)) {
            if ($this->photo_file == '#DELETEME#') {
                $data['photo_file'] = null;
            } else {
                $data['photo_file'] = $this->photo_file;
            }
        }

        if (stripos($this->path_correspondence ?? '', '($p') !== false) {
            $data['path_correspondence_default'] = $this->path_correspondence;
        }
        if (empty($this->path_correspondence)) {
            $data['path_correspondence_default'] = null;
        }

        if (stripos($this->path_inbox ?? '', '($p') !== false) {
            $data['path_inbox_default'] = $this->path_inbox;
        }
        if (empty($this->path_inbox)) {
            $data['path_inbox_default'] = null;
        }

        if (stripos($this->path_outbox ?? '', '($p') !== false) {
            $data['path_outbox_default'] = $this->path_outbox;
        }
        if (empty($this->path_outbox)) {
            $data['path_outbox_default'] = null;
        }

        if (stripos($this->path_drawings ?? '', '($p') !== false) {
            $data['path_drawings_default'] = $this->path_drawings;
        }
        if (empty($this->path_drawings)) {
            $data['path_drawings_default'] = null;
        }

        if ($this->add_or_id !== 'add') {
            unset($data['work_area_category_id']);
        }

        return $data;
    }

    /**
     * Prepare a path with values
     * 
     * @param   string  $path   The path
     * @return  string
     */
    public function prepare_path_from_values($path) {
        if (empty($path)) {
            return null;
        }

        $this->CI->load->library('upload');

        if (empty($this->project_number)) {
            if (is_numeric($this->add_or_id)) {
                $pid = '_KeineNr_' . $this->add_or_id;
            } else {
                $key = preg_replace('/[^0-9]/' . (UTF8_ENABLED ? 'u' : ''), '', $this->project_name);
                if (empty($key)) {
                    $key = soundex($this->project_name);
                }
                $pid = '_KeineNr_' . metaphone($this->project_name, 10) . '_' . $key;
            }
        } else {
            $pid = trim($this->project_number);
        }
        $pid = str_replace('/', '_', $pid); //Replace / with 
        $pid = $this->CI->upload->clean_file_name($pid);
        $path = str_ireplace('($pid)', $pid, $path);

        preg_match_all('/\(\$pid([+-][0-9]+)\)/', $path, $matches, PREG_SET_ORDER);
        foreach ($matches as $match) {
            $pid_part = substr($pid, 0, $match[1]);
            $path = str_ireplace($match[0], $pid_part, $path);
        }

        $project_name = $this->CI->upload->clean_file_name(trim($this->project_name));
        $path = str_ireplace('($pname)', $project_name, $path);

        if (empty($this->start_date) || $this->start_date->is_null()) {
            $now = new UsDate('now');
            $path = str_ireplace('($pyear)', $now->format('Y'), $path);
        } else {
            $path = str_ireplace('($pyear)', $this->start_date->format('Y'), $path);
        }

        if (empty($this->location)) {
            $path = str_ireplace('($plocation)', 'Unbekannter Ort', $path);
        } else {
            $path = str_ireplace('($plocation)', trim($this->location), $path);
        }

        return $path;
    }

    /**
     * Update paths with values
     *
     * @return  void 
     */
    public function update_all_paths_from_values() {
        $this->orig_translated_structure_tree_root_node = $this->prepare_path_from_values($this->orig_translated_structure_tree_root_node);
        $this->path_correspondence = $this->prepare_path_from_values($this->path_correspondence);
        $this->path_inbox = $this->prepare_path_from_values($this->path_inbox);
        $this->path_outbox = $this->prepare_path_from_values($this->path_outbox);
        $this->path_drawings = $this->prepare_path_from_values($this->path_drawings);
    }

    /**
     * Update paths with values
     *
     * @return  void 
     */
    public function update_all_paths_from_default_values() {
        if (!isset($this->current_project_object)) {
            basic_error('Please use set_current_project_object() before calling get_project_to_save()', $mode, __CLASS__ . '::' . __FUNCTION__);
        }
        if (!empty($this->current_project_object->path_correspondence_default)) {
            $this->path_correspondence = $this->prepare_path_from_values($this->current_project_object->path_correspondence_default);
        }
        if (!empty($this->current_project_object->path_inbox_default)) {
            $this->path_inbox = $this->prepare_path_from_values($this->current_project_object->path_inbox_default);
        }
        if (!empty($this->current_project_object->path_outbox_default)) {
            $this->path_outbox = $this->prepare_path_from_values($this->current_project_object->path_outbox_default);
        }
        if (!empty($this->current_project_object->path_drawings_default)) {
            $this->path_drawings = $this->prepare_path_from_values($this->current_project_object->path_drawings_default);
        }
    }

    /**
     * Prepare a path - clean
     * 
     * @param   string  $path   The path
     * @return  string
     */
    public function prepare_path_clean($path) {
        if (empty($path)) {
            return null;
        }

        $this->CI->load->library('upload');
        if (strtolower(substr($path, 0, 5)) === 'o365:') {
            $path = str_replace('\\', '/', $path);
        } elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            $path = $this->CI->upload->clean_file_name($path, true);
        } else {
            $path = str_replace(
                    array(
                '<',
                '>',
                '?',
                '"',
                ':',
                '|',
                '*',
                    ), '_', $path
            );
        }
        
        return rtrim($path, '.');
    }

    /**
     * Replace folder translation
     * 
     * Call before clean_paths()
     * 
     * @return  void
     */
    public function replace_folder_translation() {
        $this->CI->load->model('Folder_translation_model', 'folder_translation');

        $auto_translate_project_paths = $this->CI->folder_translation->get_auto_translate_project_paths();

        $prep_main = mb_strtolower($this->orig_translated_structure_tree_root_node ?? '');
        $prep_correspondence = mb_strtolower($this->path_correspondence ?? '');
        $prep_inbox = mb_strtolower($this->path_inbox ?? '');
        $prep_outbox = mb_strtolower($this->path_outbox ?? '');
        $prep_drawings = mb_strtolower($this->path_drawings ?? '');

        $replaced_main = false;
        $replaced_correspondence = false;
        $replaced_inbox = false;
        $replaced_outbox = false;
        $replaced_drawings = false;
        foreach ($auto_translate_project_paths as $auto_translate_project_path) {
            $prep_trans_path = $this->clean_path(mb_strtolower($auto_translate_project_path->trans_path));

            if (!$replaced_main && stripos($prep_main, $prep_trans_path) !== false) {
                $this->orig_translated_structure_tree_root_node = str_ireplace($prep_trans_path, $auto_translate_project_path->path, $this->orig_translated_structure_tree_root_node);
                $replaced_main = true;
            }

            if (!$replaced_correspondence && stripos($prep_correspondence, $prep_trans_path) !== false) {
                $this->path_correspondence = str_ireplace($prep_trans_path, $auto_translate_project_path->path, $this->path_correspondence);
                $replaced_correspondence = true;
            }

            if (!$replaced_inbox && stripos($prep_inbox, $prep_trans_path) !== false) {
                $this->path_inbox = str_ireplace($prep_trans_path, $auto_translate_project_path->path, $this->path_inbox);
                $replaced_inbox = true;
            }

            if (!$replaced_outbox && stripos($prep_outbox, $prep_trans_path) !== false) {
                $this->path_outbox = str_ireplace($prep_trans_path, $auto_translate_project_path->path, $this->path_outbox);
                $replaced_outbox = true;
            }

            if (!$replaced_drawings && stripos($prep_drawings, $prep_trans_path) !== false) {
                $this->path_drawings = str_ireplace($prep_trans_path, $auto_translate_project_path->path, $this->path_drawings);
                $replaced_drawings = true;
            }

            if ($replaced_main && $replaced_correspondence && $replaced_inbox && $replaced_outbox && $replaced_drawings) {
                return;
            }
        }
    }

    /**
     * Update paths - clean
     *
     * @return  void
     */
    public function clean_paths() {
        $old_global = $this->orig_translated_structure_tree_root_node;
        $old_corr = $this->path_correspondence;
        $old_inb = $this->path_inbox;
        $old_outb = $this->path_outbox;
        $old_draw = $this->path_drawings;

        if ($this->add_or_id === 'add') {
            if ($this->projectadmin_create_dir) {
                $this->orig_translated_structure_tree_root_node = $this->prepare_path_clean($this->orig_translated_structure_tree_root_node);
                $this->path_correspondence = $this->prepare_path_clean($this->path_correspondence);
                $this->path_inbox = $this->prepare_path_clean($this->path_inbox);
                $this->path_outbox = $this->prepare_path_clean($this->path_outbox);
                $this->path_drawings = $this->prepare_path_clean($this->path_drawings);
            }
        } else {
            if (!isset($this->current_project_object)) {
                basic_error('Please use set_current_project_object() before calling get_project_to_save()', $mode, __CLASS__ . '::' . __FUNCTION__);
            }
            if ($this->projectadmin_create_dir && $this->orig_translated_structure_tree_root_node != $this->current_project_object->orig_translated_structure_tree_root_node) {
                $this->orig_translated_structure_tree_root_node = $this->prepare_path_clean($this->orig_translated_structure_tree_root_node);
            }

            if ($this->projectadmin_create_dir && $this->path_correspondence != $this->current_project_object->path_correspondence) {
                $this->path_correspondence = $this->prepare_path_clean($this->path_correspondence);
            }

            if ($this->projectadmin_create_dir && $this->path_inbox != $this->current_project_object->path_inbox) {
                $this->path_inbox = $this->prepare_path_clean($this->path_inbox);
            }

            if ($this->projectadmin_create_dir && $this->path_outbox != $this->current_project_object->path_outbox) {
                $this->path_outbox = $this->prepare_path_clean($this->path_outbox);
            }

            if ($this->projectadmin_create_dir && $this->path_drawings != $this->current_project_object->path_drawings) {
                $this->path_drawings = $this->prepare_path_clean($this->path_drawings);
            }
        }

        $this->orig_translated_structure_tree_root_node_cleaned = ($old_global != $this->orig_translated_structure_tree_root_node) ? true : false;
        $this->path_correspondence_cleaned = ($old_corr != $this->path_correspondence) ? true : false;
        $this->path_inbox_cleaned = ($old_inb != $this->path_inbox) ? true : false;
        $this->path_outbox_cleaned = ($old_outb != $this->path_outbox) ? true : false;
        $this->path_drawings_cleaned = ($old_draw != $this->path_drawings) ? true : false;
    }

    /**
     * Validate paths
     *
     * @return  string  Message 
     */
    public function ensure_paths_exists() {
        $msg = '';
        if (strtolower($this->add_or_id) === 'add' && $this->structure_id > 0) {//for adding structure tree
            $this->CI->load->model('Project_directory_structure_tree_model', 'project_directory_structure_tree');
            $seperator = '/';
            if (strpos($this->structure_tree_root_node, '\\') !== false) {
                $seperator = '\\';
            }

            $nodes = $this->tree; //prepared in ::init_from_post()
            $root_path = $this->prepare_path_from_values($this->structure_tree_root_node);
            $paths_and_files = new stdClass();
            $paths_and_files->paths = array();
            $paths_and_files->files = array();
            $paths_and_files->paths[] = $root_path; //Always create root path
            if (is_array($nodes)) {
                foreach ($nodes as $node) {
                    $this->structure_tree_root_node . $this->_prepare_node_path($paths_and_files, $node, $seperator, $root_path); //&$paths
                }
            }

            $msg .= $this->CI->project_directories_tools->ensure_path_exists($root_path, true);
            foreach ($paths_and_files->paths as $path) {
                $msg .= $this->CI->project_directories_tools->ensure_path_exists($path, true);
            }

            foreach ($paths_and_files->files as $file) {
                $msg .= $this->CI->project_directories_tools->copy_file($file->from, $file->to);
            }
        } else {
            $msg .= $this->CI->project_directories_tools->ensure_path_exists($this->path_correspondence, $this->projectadmin_create_dir);
            $msg .= $this->CI->project_directories_tools->ensure_path_exists($this->path_inbox, $this->projectadmin_create_dir);
            $msg .= $this->CI->project_directories_tools->ensure_path_exists($this->path_outbox, $this->projectadmin_create_dir);
            $msg .= $this->CI->project_directories_tools->ensure_path_exists($this->path_drawings, $this->projectadmin_create_dir);
        }
        return $msg;
    }

    /**
     * Prepare node paths recursive
     * 
     * @param object    $paths_and_files    The paths object where all paths are collected
     * @param object    $node               The actual node
     * @param string    $seperator          The path separator
     * @param string    $last_path          The last path
     * 
     * @return void
     */
    private function _prepare_node_path($paths_and_files, $node, $seperator, $last_path) {
        if ($this->CI->load->filesystem($node->name) instanceof O365_filesystem_creator) {
            $node->name = trim($node->name, '/');
            $last_path = '';
        }

        if ($node->file !== null) {
            $a_from_ext = explode('.', $node->file);
            $a_to_ext = explode('.', $last_path . $node->name);
            if (is_array($a_from_ext) && count($a_from_ext) > 1) {
                $from_ext = $a_from_ext[count($a_from_ext) - 1];
                $to_ext = $a_to_ext[count($a_to_ext) - 1];
                if (($from_ext !== $to_ext)) {
                    $last_path . $node->name.= '.' . $from_ext;
                }
            }

            $path = $last_path . $node->name;
            $tmp = new stdClass();
            $tmp->from = $node->file;
            $tmp->to = $this->CI->project_directory_structure_tree->create_absolute_filename($path);
            $tmp->to = $this->prepare_path_from_values($tmp->to);
            $paths_and_files->files[] = $tmp;
        } else {
            $path = $this->prepare_path_from_values($last_path . $node->name);
            $path.= $seperator;
            $paths_and_files->paths[] = $path;
        }

        if (is_array($node->CHILDREN) && count($node->CHILDREN) > 0) {
            foreach ($node->CHILDREN AS $my_node) {
                $this->_prepare_node_path($paths_and_files, $my_node, $seperator, $path);
            }
        }
    }

    /**
     * Get the cleaned message
     * 
     * @return  string
     */
    public function get_cleaned_message() {
        $msg = '';
        if ($this->orig_translated_structure_tree_root_node_cleaned) {
            $msg .= $this->CI->lang->linef('projectadmin_path_cleaned', $this->orig_translated_structure_tree_root_node) . '<br />';
        }
        if ($this->path_correspondence_cleaned) {
            $msg .= $this->CI->lang->linef('projectadmin_path_cleaned', $this->path_correspondence) . '<br />';
        }
        if ($this->path_inbox_cleaned) {
            $msg .= $this->CI->lang->linef('projectadmin_path_cleaned', $this->path_inbox) . '<br />';
        }
        if ($this->path_outbox_cleaned) {
            $msg .= $this->CI->lang->linef('projectadmin_path_cleaned', $this->path_outbox) . '<br />';
        }
        if ($this->path_drawings_cleaned) {
            $msg .= $this->CI->lang->linef('projectadmin_path_cleaned', $this->path_drawings) . '<br />';
        }
        return $msg;
    }

    /**
     * Get path values
     *
     * @return  array 
     */
    public function get_paths() {
        return array(
            $this->path_correspondence,
            $this->path_inbox,
            $this->path_outbox,
            $this->path_drawings,
        );
    }

    /**
     * Check if we are creating an copy(duplicate)
     * 
     * @return boolean 
     */
    public function is_new_copy() {
        if ($this->add_or_id === 'add' && $this->old_id > 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Get the old ID
     *
     * @return mixed    Either the old_id or false if no copy(duplicate) 
     */
    public function get_old_id() {
        if ($this->is_new_copy()) {
            return $this->old_id;
        } else {
            return false;
        }
    }

    /**
     * Set the current project object
     *
     * @param   object  $current_project_object     The current project
     * @return  void
     */
    public function set_current_project_object($current_project_object) {
        $this->current_project_object = $current_project_object;
    }

    /**
     * Get work area category ID
     * 
     * @return  integer
     */
    public function get_work_package_presets_id() {
        return $this->work_package_preset_id;
    }

    /**
     * Set the work area category ID
     * 
     * @param   integer     $work_package_preset_id      Set work package ID
     * @return  void
     */
    public function set_work_package_presets_id($work_package_preset_id) {
        $this->work_package_preset_id = $work_package_preset_id;
    }

    /**
     * Create the directories, if not exists
     *
     * @return  boolean
     */
    public function get_projectadmin_create_dir() {
        return $this->projectadmin_create_dir;
    }

    /**
     * Get structure ID (Only use on new)
     * 
     * @return  mixed   Either integer or false if none
     */
    public function get_structure_id() {
        if (!is_numeric($this->structure_id)) {
            return false;
        }

        if ($this->structure_id <= 0) {
            return false;
        }

        return intval($this->structure_id);
    }

    /**
     * Get project name
     * 
     * @return  string
     */
    public function get_project_name() {
        return $this->rem_newlines($this->project_name);
    }

    /**
     * Get project number
     * 
     * @return  string
     */
    public function get_project_number() {
        return $this->rem_newlines($this->project_number);
    }

    /**
     * Get project structure tree note path
     * 
     * @return  string
     */
    public function get_orig_translated_structure_tree_root_node() {
        return $this->orig_translated_structure_tree_root_node;
    }

    /**
     * Get flink2go ID to create
     * 
     * @return  mixed   Either false or the ID
     */
    public function get_flink2go_create() {
        if ($this->flink2go_create <= 0) {
            return false;
        }
        return intval($this->flink2go_create);
    }

    /**
     * Get realview ID to create
     * 
     * @return  mixed   Either false or the ID
     */
    public function get_realview_create() {
        if ($this->realview_create <= 0) {
            return false;
        }
        return intval($this->realview_create);
    }

    /**
     * Get dokspace url ID to create
     * 
     * @return  mixed   Either false or the ID
     */
    public function get_dokspace_url_create() {
        if ($this->dokspace_url_create <= 0) {
            return false;
        }

        return intval($this->dokspace_url_create);
    }
    
    /**
     * Get 
     * 
     * @return boolean
     */
    public function get_work_package_preset_chk_box() {
        return $this->work_package_preset_chk_box;
    }
    
    /**
     * Returns the names of all variables of this object that should be serialized
     *
     * @return  array
     */
    public function __sleep()
    {
        return array(
            "old_id",
            "project_name",
            "project_number",
            "location",
            "purpose",
            "photo_file",
            "project_category_id",
            "start_date",
            "end_date",
            "project_manager_id",
            "division_manager_id",
            "client_id",
            "office_in_charge_id",
            "project_phase_id",
            "project_archive_id",
            "safekeeping_period",
            "measurement_value",
            "measurement_id",
            "is_add_to_indirect_costs",
            "is_private_project",
            "ignore_required_purpose",
            "work_area_category_id",
            "path_correspondence",
            "default_extras",
            "default_discount",
            "default_discount_days",
            "sync_correspondence",
            "path_inbox",
            "sync_inbox",
            "path_outbox",
            "sync_outbox",
            "path_drawings",
            "work_package_preset_id",
            "work_package_preset_chk_box",
            "flink2go_create",
            "realview_create",
            "dokspace_url_create",
            "projectadmin_create_dir",
            "current_project_object",
            "orig_translated_structure_tree_root_node_cleaned",
            "path_correspondence_cleaned",
            "path_inbox_cleaned",
            "path_outbox_cleaned",
            "path_drawings_cleaned",
            "structure_id",
            "structure_tree_root_node",
            "orig_structure_tree_root_node",
            "orig_translated_structure_tree_root_node",
            "tree",
        );
    }
    
    /**
     * Reconstruct any resources
     *
     * @return  void
     */
    public function __wakeup()
    {
        $this->CI = CI_Controller::get_instance();
    }
    
}

