/**
  * Create an array will the valid items for search and replacing with templates
  *
  * @static
  *
  * @param $type
  * @param $database
  * @param $table
  * @param $class
  * @param $namespace
  *
  * @return array
  *
  * @throws \Exception
  */
 private static function buildSearchReplaceArray($type, $database, $table, $class, $namespace)
 {
     $database = Configuration::getTrueDatabaseName($database);
     $builderConfiguration = Configuration::getOption('model_builder');
     $tableConfiguration = $builderConfiguration['relational']['databases'][$database]['tables'];
     $tableAlias = !empty($tableConfiguration[$table]['alias']) ? $tableConfiguration[$table]['alias'] : $table;
     $dataSource = DataSourceFactory::buildFromConfiguration('default');
     $parsingTokens = array();
     $stringReplaceArray = array();
     if ($type == 'full') {
         foreach (self::$templateTokens as $tokens) {
             $parsingTokens = array_merge($parsingTokens, $tokens);
         }
     } else {
         if (array_key_exists($type, self::$templateTokens)) {
             $parsingTokens = self::$templateTokens[$type];
         } else {
             throw new \Exception("Invalid type ({$type}) for building token list");
         }
     }
     $autoIncrementField = null;
     $primaryKeyArray = array();
     $tableArray = array('name' => $table, 'alias' => $tableAlias);
     $fieldsArray = array();
     $skipSaveMembersArray = !empty($tableConfiguration[$table]['skip_save_members']) ? $tableConfiguration[$table]['skip_save_members'] : array();
     $tableFieldDetails = $dataSource->getTableFieldsDetails($table, $database);
     foreach ($tableFieldDetails as $fieldDetails) {
         if ($fieldDetails['auto_increment'] === true) {
             $autoIncrementField = $fieldDetails['field'];
         }
         if ($fieldDetails['key_type'] == 'primary') {
             $primaryKeyArray[] = $fieldDetails['field'];
         }
         $memberNameParts = explode('_', RegexHelper::toUnderscore($fieldDetails['field']));
         $memberName = '';
         foreach ($memberNameParts as $part) {
             $memberName .= ucwords(strtolower($part));
         }
         $memberName = lcfirst($memberName);
         $fieldsArray[$memberName] = array('name' => $fieldDetails['field']);
         if (in_array($fieldDetails['field_type'], array('enum', 'set'))) {
             $fieldsArray[$memberName]['values'] = $dataSource->getFieldValues($table, $fieldDetails['field'], $database);
         }
     }
     //add in join fields
     if (!empty($tableConfiguration[$table]['join_fields'])) {
         foreach ($tableConfiguration[$table]['join_fields'] as $joinTable => $fields) {
             foreach ($fields as $options) {
                 $memberName = !empty($options['member_name']) ? $options['member_name'] : $options['field'];
                 $field = $options['field'];
                 $as = $options['field'];
                 if (!empty($options['as'])) {
                     $as = $options['as'];
                 } else {
                     if (!empty($options['member_name'])) {
                         $as = $options['member_name'];
                     }
                 }
                 $joinFieldData = array('name' => $field, 'join_table' => $joinTable);
                 if ($as != $options['field']) {
                     $joinFieldData['name'] .= ' AS ' . $as;
                 }
                 $fieldsArray[$memberName] = $joinFieldData;
             }
         }
     }
     foreach ($parsingTokens as $token) {
         $trueValue = null;
         switch ($token) {
             case 'namespace':
                 $trueValue = $namespace;
                 break;
             case 'class':
                 $trueValue = $class;
                 break;
             case 'database':
                 $trueValue = $database;
                 break;
             case 'primaryKeyArray':
                 $trueValue = self::arrayToPhpCodeString($primaryKeyArray);
                 break;
             case 'autoIncrementField':
                 $trueValue = $autoIncrementField;
                 break;
             case 'tableArray':
                 $trueValue = self::arrayToPhpCodeString($tableArray);
                 break;
             case 'joinsArray':
                 $joinsArray = array();
                 if (!empty($tableConfiguration[$table]['joins'])) {
                     foreach ($tableConfiguration[$table]['joins'] as $joinTable => $config) {
                         $temp['alias'] = !empty($tableConfiguration[$joinTable]['alias']) ? $tableConfiguration[$joinTable]['alias'] : $joinTable;
                         $temp['type'] = !empty($config['type']) ? $config['type'] : 'inner';
                         $temp['on'] = "`{$temp['alias']}`.`{$config['join_field']}` = `{$tableAlias}`.`{$config['field']}`";
                         if (!empty($config['database'])) {
                             $temp['database'] = $config['database'];
                         }
                         $joinsArray[$joinTable] = $temp;
                     }
                 }
                 $trueValue = self::arrayToPhpCodeString($joinsArray);
                 break;
             case 'fieldsArray':
                 $trueValue = self::arrayToPhpCodeString($fieldsArray);
                 break;
             case 'dataSourceConfiguration':
                 $trueValue = 'default';
                 break;
             case 'skipSaveMembersArray':
                 $trueValue = self::arrayToPhpCodeString($skipSaveMembersArray);
                 break;
             case 'fields':
                 $trueValue = '';
                 foreach ($fieldsArray as $member => $options) {
                     if (!empty($trueValue)) {
                         $trueValue .= "\n";
                     } else {
                         $trueValue .= "\n\n";
                     }
                     $trueValue .= "    protected \${$member};";
                 }
                 break;
             default:
                 throw new \Exception("Token passed ({$token}) is not a valid token");
                 break;
         }
         $stringReplaceArray[self::$tokenWrapper . $token . self::$tokenWrapper] = $trueValue;
     }
     return $stringReplaceArray;
 }
 /**
  * The implementation of what the command should do when executed
  *
  * @param \Symfony\Component\Console\Input\InputInterface $input
  * @param \Symfony\Component\Console\Output\OutputInterface $output
  */
 public function execute(InputInterface $input, OutputInterface $output)
 {
     $builderConfiguration = Configuration::getOption('model_builder');
     $basePath = $builderConfiguration['base_source_path'];
     $basePath = substr($basePath, 0, 1) === DIRECTORY_SEPARATOR ? $basePath : __DIR__ . DIRECTORY_SEPARATOR . $basePath;
     /*echo "\n\n";
     		var_dump($basePath);
     		echo "\n\n";
     		exit();*/
     $defaultNamespace = $builderConfiguration['relational']['default_namespace'];
     $dataSource = DataSourceFactory::buildFromConfiguration('default');
     $options = $input->getOptions();
     $databases = $options['database'] ? array($options['database']) : array();
     if (empty($databases)) {
         foreach ($builderConfiguration['relational']['databases'] as $databaseName => $databaseOptions) {
             $databases[] = $databaseName;
         }
     }
     foreach ($databases as $database) {
         $tableConfiguration = $builderConfiguration['relational']['databases'][$database]['tables'];
         $table = $input->getArgument('table');
         if (!empty($table)) {
             $tables = array($input->getArgument('table'));
         } else {
             $tables = $dataSource->getTables($database);
         }
         $dialog = $this->getHelperSet()->get('dialog');
         $output->writeln('');
         $output->writeln("Writing models for {$database} database:");
         foreach ($tables as $table) {
             if (isset($tableConfiguration[$table])) {
                 $classDefault = !empty($tableConfiguration[$table]['class_name']) ? $tableConfiguration[$table]['class_name'] : null;
                 //todo: add in the ability to get class name during this process if one if not set
                 $class = $options['default'] === true ? $classDefault : $options['class'];
                 if (!empty($class)) {
                     $namespace = $options['default'] === true ? $builderConfiguration['relational']['default_namespace'] : $options['namespace'];
                     $namespace .= "\\{$database}";
                     while (empty($namespace)) {
                         if ($namespace === null) {
                             $output->writeln('You must specify a namespace for the class');
                         }
                         $message = "What would you like the namespace name for class {$class} to be";
                         if (!empty($defaultNamespace)) {
                             $message .= ' [' . $defaultNamespace . ']';
                         }
                         $namespace = $dialog->ask($output, "{$message}? ");
                         if (!empty($defaultNamespace) && empty($namespace)) {
                             $namespace = $defaultNamespace;
                         }
                     }
                     if (empty($database)) {
                         $output->writeln("ERROR: Can't build model without database being specified int he command of in the connection\\s configuration");
                         return;
                     }
                     $namespaceParts = explode('\\', $namespace);
                     $extraFilePath = implode('/', $namespaceParts);
                     $filePath = "{$basePath}/{$extraFilePath}/{$class}.php";
                     //make sure that directory exists
                     if (!is_dir("{$basePath}/{$extraFilePath}")) {
                         //todo: make directory mode configurable
                         mkdir("{$basePath}/{$extraFilePath}", 0777, true);
                     }
                     if (file_exists($filePath)) {
                         $phpCode = \Salvo\Barrage\Utility\ModelBuilder::updateModelClass($filePath, $database, $table, $class, $namespace);
                     } else {
                         $phpCode = \Salvo\Barrage\Utility\ModelBuilder::buildModelClass($database, $table, $class, $namespace);
                     }
                     $this->writeFile($filePath, $phpCode);
                     $output->writeln("Writing model for the {$table} table as class {$class} to {$filePath}");
                 }
             }
         }
         $output->writeln('');
     }
 }