<?php
/**
 * i-doit - Documentation and CMDB solution for IT environments
 *
 * This file is part of the i-doit framework. Modify at your own risk.
 *
 * Please visit http://www.i-doit.com/license for a full copyright and license information.
 *
 * @version     1.10
 * @package     i-doit
 * @author      synetics GmbH
 * @copyright   synetics GmbH
 * @url         http://www.i-doit.com
 * @license     http://www.i-doit.com/license
 */

namespace idoit\Console\Command\Import\Csv;

use idoit\Component\Logger;
use idoit\Console\Command\AbstractCommand;
use idoit\Console\Exception\MissingFileException;
use isys_format_json;
use isys_module_dao_import_log;
use isys_module_import_csv;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class ImportCsvCommand extends AbstractCommand
{
    const NAME = 'import-csv';

    private static $multiValueModes = [
        'row',
        'column',
        'comma'
    ];

    /**
     * Get name for command
     *
     * @return string
     */
    public function getCommandName()
    {
        return self::NAME;
    }

    /**
     * Get description for command
     *
     * @return string
     */
    public function getCommandDescription()
    {
        return 'Imports CSV formatted files (Using a predefined CSV Import filter, defined in the GUI)';
    }

    /**
     * Retrieve Command InputDefinition
     *
     * @return InputDefinition
     */
    public function getCommandDefinition()
    {
        $definition = new InputDefinition();
        $definition->addOption(new InputOption(
            'importFile',
            null,
            InputOption::VALUE_REQUIRED,
            'CSV file for import'
        ));
        $definition->addOption(new InputOption(
            'importProfileId',
            null,
            InputOption::VALUE_REQUIRED,
            'Profile which should be used to map import file'
        ));
        $definition->addOption(new InputOption(
            'csvSeparator',
            null,
            InputOption::VALUE_REQUIRED,
            'Separator of import file'
        ));
        $definition->addOption(new InputOption(
            'multiValueMode',
            null,
            InputOption::VALUE_REQUIRED,
            'Multivalue mode. Possible modes are "row", "column" or "comma"'
        ));

        return $definition;
    }

    /**
     * Checks if a command can have a config file via --config
     *
     * @return bool
     */
    public function isConfigurable()
    {
        return true;
    }

    /**
     * Returns an array of command usages
     *
     * @return string[]
     */
    public function getCommandUsages()
    {
        return [
            '-u admin -p admin -i 1 --importFile /var/www/imports/idoit-Demo-CSV-Import.csv --importProfileId 1 --csvSeparator ";" --multiValueMode column'
        ];
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln('<info>csv-Import handler initialized at </info>' . date('Y-m-d H:i:s'));

        try
        {
            $this->process($input, $output);
        }
        catch (\Exception $e)
        {
            $output->writeln('<error>' . $e->getMessage() . '</error>');
        } // try
    }

    private function process(InputInterface $input, OutputInterface $output)
    {
        // Initialize:
        $l_file                   = $input->getOption('importFile');
        $l_profile_id             = $input->getOption('importProfileId');
        $l_delimiter              = $input->getOption('csvSeparator');
        $l_multivalue_mode        = $input->getOption('multiValueMode');
        $l_object_type_assignment = [];
        $l_identificationCounter  = 1;

        // Ensure that setted multivalue mode is valid.
        if (!in_array($l_multivalue_mode, self::$multiValueModes)) {
            throw new InvalidArgumentException(
                sprintf(
                    'Given mode %s is not allowed, choose one of these: %s',
                    $l_multivalue_mode,
                    implode(',', self::$multiValueModes)
                )
            );
        } // if

        // Check file:
        if (!file_exists($l_file))
        {
            throw new MissingFileException('File "' . $l_file . '" does not exist.');
        } // if

        // Load Profile.
        if (is_numeric($l_profile_id))
        {
            $l_profiles = isys_module_import_csv::get_profiles($l_profile_id);
            $output->writeln('Retrieve profile with id #' . $l_profile_id . '...');

            if (is_array($l_profiles) && count($l_profiles))
            {
                // Get first profile.
                $l_profile = $l_profiles[0];

                // Decode data attribute into array.
                $l_profile['data'] = isys_format_json::decode($l_profile['data']);

                // Check for filled profile
                if (is_array($l_profile['data']))
                {
                    // Some transformation work
                    $l_key_data               = [];
                    $l_transformed_assignment = [];

                    foreach ($l_profile['data']['assignments'] AS $l_index => $l_data)
                    {
                        if (empty($l_data['category']))
                        {
                            continue;
                        } // if

                        // Empty property means we have object_title, category.
                        if (!defined($l_data['category']) && empty($l_data['property']))
                        {
                            $l_key_data[$l_data['category']] = $l_index;
                        }
                        else
                        {
                            if(strpos(isys_module_import_csv::CL__MULTIVALUE_TYPE__COLUMN, $l_multivalue_mode) === false)
                            {
                                $l_transformed_assignment[$l_data['category']][$l_data['property']] = $l_index;
                            }
                            else
                            {
                                $l_transformed_assignment[$l_index] = $l_data;
                            }

                            if (isset($l_data['object_type']) && isset($l_data['create_object']))
                            {
                                $l_object_type_assignment[$l_index] = [
                                    'object-type'   => $l_data['object_type'],
                                    'create-object' => (int) $l_data['create_object']
                                ];
                            } // if
                        } // if
                    } // foreach
                }
                else
                {
                    throw new RuntimeException('Profile does not have any data.');
                } // if

                $output->writeln('Profile ' . $l_profile['title'] . ' succesfully loaded.');
            }
            else
            {
                throw new RuntimeException('Unable to load profile with ID #' . $l_profile_id);
            } // if
        }
        else
        {
            throw new InvalidArgumentException('The given profile ID is not numeric');
        } // if

        // Collect necessary information for the import process
        $output->writeln('Initializing csv-import...');

        if (defined($l_profile['data']['globalObjectType']))
        {
            $l_profile['data']['globalObjectType'] = constant($l_profile['data']['globalObjectType']);
        } // if

        // Initialize csv module
        $l_module_csv = new isys_module_import_csv(
            $l_file,
            $l_delimiter,
            $l_multivalue_mode,
            $l_key_data['object_title'],
            $l_profile['data']['globalObjectType'],
            $l_key_data['object_type_dynamic'],
            $l_key_data['object_purpose'],
            $l_key_data['object_category'],
            $l_key_data['object_sysid'],
            $l_key_data['object_cmdbstatus'],
            $l_key_data['object_description'],
            (bool) $l_profile['data']['headlines'],
            $l_profile['data']['additionalPropertySearch'],
            $l_profile['data']['multivalueUpdateMode'],
            Logger::INFO
        );

        if (count($l_profile['data']['identificationKeys']) > 0)
        {
            $l_csv_idents  = [];
            $l_identifiers = [];

            // See ID-4162
            if (isset($l_profile['data']['identificationCounter']) && $l_profile['data']['identificationCounter'] > 1)
            {
                $l_identificationCounter = (int) $l_profile['data']['identificationCounter'];
            } // if

            foreach ($l_profile['data']['identificationKeys'] AS $l_data)
            {
                $l_csv_idents[]  = $l_data['csvIdent'];
                $l_identifiers[] = $l_data['localIdent'];
            }

            $output->writeln('Found ' . count($l_profile['data']['identificationKeys']) . ' identification fields of which at least ' . $l_identificationCounter . ' need to match!');
        } // if

        $l_module_csv->initialize($l_transformed_assignment, $l_object_type_assignment);

        // Trigger import.
        $l_module_csv->import();

        // ID-2890 - Log changes.
        $l_import_dao   = new isys_module_dao_import_log($this->container->database);
        $l_import_entry = $l_import_dao->add_import_entry(
            $l_import_dao->get_import_type_by_const('C__IMPORT_TYPE__CSV'),
            str_replace(C__IMPORT__CSV_DIRECTORY, '', $l_file),
            null // (((bool) $_POST['profile_loaded']) ? $_POST['profile_sbox'] : null) // What is this field for?
        );

        $l_module_csv->save_log($l_import_entry);

        // Output log
        if (file_exists($l_module_csv->get_log_path()) && is_readable($l_module_csv->get_log_path()))
        {
            $output->writeln(file_get_contents($l_module_csv->get_log_path()));
        } // if

        $output->writeln("Successfully imported data.");
    }
}
