/**
  * Create Edit or Save a Translation File
  */
 function edit_language()
 {
     global $option;
     // import file functions
     jimport('joomla.filesystem.file');
     // variables
     global $mainframe;
     $options = Language_manager::getOptions();
     $options['newprocess'] = 0;
     // build the search highlight array
     $options['filter_search'] = $mainframe->getUserStateFromRequest($option . '.files.filter_search', 'filter_search', '');
     // 2: otherwise verify that we have a filename
     // 3: otherwise validate the checkout status of the selected file
     if (empty($options['filename'])) {
         $mainframe->enqueueMessage(JText::_('You must select a file to edit'));
         $mainframe->redirect('index.php?option=' . $option . '&task=language_files');
     } else {
         if ($content = @file_get_contents($options['langPath'] . DS . 'chk.' . $options['filename'])) {
             list($timestamp, $userid, $username) = explode('#', $content . '##');
             $user =& JFactory::getUser();
             // validate the checkout
             if (time() - $timestamp < 3600 && $userid != 0 && $userid != $user->get('id', '0')) {
                 // report and redirect
                 $checkin = '<a href="index.php?option=' . $option . '&task=checkin&id=' . $options['filename'] . '" title="' . JText::_('Force Checkin') . '" style="font-size:smaller">[' . JText::_('Checkin') . ']</a>';
                 $mainframe->enqueueMessage(sprintf(JText::_('checked out by'), $options['filename'], $username, $checkin));
                 $mainframe->redirect('index.php?option=' . $option . '&task=language_files');
             }
         }
     }
     // set the reference language filename from the selected filename
     $options['refFilename'] = str_replace($options['lang'], $options['refLang'], $options['filename']);
     // find the published reference language file
     // default to an unpublished reference file
     if (JFile::exists($options['refLangPath'] . DS . $options['refFilename'])) {
         $options['ref_path_file'] = $options['refLangPath'] . DS . $options['refFilename'];
     } else {
         $options['ref_path_file'] = $options['refLangPath'] . DS . 'xx.' . $options['refFilename'];
     }
     // find the published selected language file
     // default to an unpublished new file
     if (JFile::exists($options['langPath'] . DS . $options['filename'])) {
         $options['path_file'] = $options['langPath'] . DS . $options['filename'];
     } else {
         $options['path_file'] = $options['langPath'] . DS . 'xx.' . $options['filename'];
     }
     // STRINGS: initialise $editData from the reference language file contents
     // $editData is an analogue of the reference file
     // header lines are skipped
     // comments and blank lines are strings with an integer index
     // key=value pairs are arrays with the key as an index
     $editData = array();
     $header = 0;
     $refStrings = array();
     if ($refContent = @file($options['ref_path_file'])) {
         foreach ($refContent as $k => $v) {
             $v = trim($v);
             // grab the comments (but skip up to 6 lines before we have any strings in the file)
             // grab the strings
             if (empty($v) || $v[0] == '#' || $v[0] == ';') {
                 if ($header++ > 6) {
                     $editData[$k] = $v;
                 }
             } else {
                 if (strpos($v, '=')) {
                     $header = 7;
                     list($key, $value) = explode('=', $v, 2);
                     $key = strtoupper($key);
                     $refStrings[$key] = $value;
                     $editData[$key] = array('ref' => $value, 'edit' => $value);
                     if ($options['isReference']) {
                         $editData[$key]['lang_file'] = $value;
                     }
                 }
             }
         }
     }
     // STRINGS: load the selected file contents and process into $editData
     // only when the selected language is not the same as the reference language
     if ($options['isReference']) {
         $fileContent = $refContent;
         $fileStrings = array();
         $fileMeta = TranslationsHelper::getINIMeta($fileContent, $fileStrings);
         $editStrings = $fileStrings;
     } else {
         if ($fileContent = @file($options['path_file'])) {
             $fileStrings = array();
             $fileMeta = TranslationsHelper::getINIMeta($fileContent, $fileStrings);
             $editStrings = $fileStrings;
             foreach ($fileStrings as $k => $v) {
                 $editData[$k]['edit'] = $v;
                 $editData[$k]['lang_file'] = $v;
             }
         } else {
             $fileContent = array();
             $fileStrings = array();
             $fileMeta = array('headertype' => 1, 'owner' => 'ff', 'complete' => 0);
             $editStrings = array();
         }
     }
     // STRINGS: load the user form contents and process into $editData
     $editFormOnly = array();
     if ($FormKeys = JRequest::getVar('ffKeys', array(), '', 'ARRAY', JREQUEST_ALLOWRAW)) {
         $FormValues = JRequest::getVar('ffValues', array(), '', 'ARRAY', JREQUEST_ALLOWRAW);
         // process each key=value pair from the form into $editData
         foreach ($FormKeys as $k => $v) {
             if ($v && isset($FormValues[$k])) {
                 $key = strtoupper(trim(stripslashes($v)));
                 $value = trim(stripslashes(str_replace('\\n', "\n", $FormValues[$k])));
                 $editStrings[$key] = $value;
                 $editData[$key]['edit'] = $value;
                 $editData[$key]['user_form'] = $value;
             }
         }
         // every element of $editData must have a form entry
         foreach ($editData as $k => $v) {
             if (is_array($v) && !isset($v['user_form'])) {
                 unset($editStrings[$k]);
                 unset($editData[$k]);
             }
         }
     }
     // META: get the XML and status meta then initialise
     $options['XMLmeta'] = TranslationsHelper::getXMLMeta($options['langPath'] . DS . $options['lang'] . '.xml');
     $statusMeta = TranslationsHelper::getINIstatus($refStrings, $editStrings);
     $editMeta = array_merge($options['XMLmeta'], $fileMeta, $statusMeta);
     $editMeta['filename'] = $options['filename'];
     // META: apply any user form values
     foreach ($editMeta as $k => $v) {
         $editMeta[$k] = JRequest::getVar($k, $v, '', 'string');
     }
     // META: require meta values
     foreach (array('version', 'author') as $v) {
         if (empty($editMeta[$v])) {
             $options['field_error_list'][$v] = JText::_($v);
         }
     }
     // ERRORS: report any errors and change the task
     if (!empty($options['field_error_list'])) {
         $mainframe->enqueueMessage(sprintf(JText::_('Values Required'), implode(', ', $options['field_error_list'])));
         $options['task'] = 'language_edit';
     }
     // create a new file or save an existing file
     if ($options['task'] == 'apply_language' || $options['task'] == 'save_language') {
         // ensure the file does not already exist when we are creating a new file
         if ($options['newprocess'] && JFile::exists($options['path_file'])) {
             // report error and set task flag
             $mainframe->enqueueMessage(sprintf(JText::_('Language INI Exists'), $options['newfilename']));
             $options['task'] = 'language_edit';
         } else {
             // check the complete status
             // we set the complete value to the number of strings that are 'unchanged'
             // so that if the reference INI file should change the 'complete' flag is unset/broken
             $editMeta['complete'] = JRequest::getVar('complete', '', 'post', 'string');
             $editMeta['complete'] = $editMeta['complete'] == 'COMPLETE' ? $editMeta['unchanged'] : 0;
             // build the header
             if ($editMeta['headertype'] == 1) {
                 $saveContent = '# $Id: ' . $options['filename'] . ' ' . $editMeta['version'] . ' ' . date('Y-m-d H:i:s') . ' ' . $editMeta['owner'] . ' ~' . $editMeta['complete'] . ' $';
             } else {
                 $saveContent = '# version ' . $editMeta['version'] . ' ' . date('Y-m-d H:i:s') . ' ~' . $editMeta['complete'];
             }
             $saveContent .= "\n" . '# author ' . $editMeta['author'];
             $saveContent .= "\n" . '# copyright ' . $editMeta['copyright'];
             $saveContent .= "\n" . '# license ' . $editMeta['license'];
             $saveContent .= "\n\n" . '# Note : All ini files need to be saved as UTF-8';
             $saveContent .= "\n\n";
             // process the $editData array to get the remaining content
             $changedStrings = array();
             $header = 0;
             foreach ($editData as $k => $v) {
                 // 1: add a blank line or comment
                 // 2: add a key=value line (no need to addslashes on quote marks)
                 if (!is_array($v)) {
                     $saveContent .= $v . "\n";
                 } else {
                     // change newlines in the value
                     $value = preg_replace('/(\\r\\n)|(\\n\\r)|(\\n)/', '\\n', $v['edit']);
                     // change single-quotes or backticks in the value
                     if ($options['backticks'] > 0) {
                         $value = strtr($value, "'", '`');
                     } else {
                         if ($options['backticks'] < 0) {
                             $value = strtr($value, '`', "'");
                         }
                     }
                     // set back to $editData
                     $editData[$k]['edit'] = $value;
                     // add to file content
                     $saveContent .= $k . '=' . $value . "\n";
                     // if the string is in the selected language file
                     if (isset($v['lang_file'])) {
                         // and it has changed (via the user form)
                         if ($v['lang_file'] != $v['edit']) {
                             // log the change in a translation array
                             $changedStrings["\n" . $k . '=' . $v['lang_file']] = "\n" . $k . '=' . $v['edit'];
                         }
                     }
                 }
             }
             // if there is no reference Language File, automatically initialise/create one which is the same as the selected language file
             if ($options['refLangMissing']) {
                 if (JFile::write($options['refLangPath'] . DS . $options['refLangFile'], trim($saveContent))) {
                     $mainframe->enqueueMessage(sprintf(JText::_('Language INI Created'), $options['refLangFile']));
                 }
             }
             // 1: write the selected language file and clear newprocess flag
             // 2: report failure
             if (JFile::write($options['path_file'], trim($saveContent))) {
                 $mainframe->enqueueMessage(sprintf(JText::_('Language INI ' . ($options['newprocess'] ? 'Created' : 'Saved')), $options['clientName'], $options['filename']));
                 $options['newprocess'] = 0;
             } else {
                 $mainframe->enqueueMessage(sprintf(JText::_('Could not write to file'), $options['path_file']));
             }
             // process changed strings globally across all the the ini files from the selected language directory
             if (count($changedStrings) && $options['globalChanges']) {
                 $write = 0;
                 $writeFiles = array();
                 if ($files = JFolder::files($options['langPath'])) {
                     foreach ($files as $file) {
                         // skip non-INI files
                         // skip this file
                         // skip this file (unpublished)
                         // skip checked out files
                         if (strtolower(substr($file, -4) != '.ini') || $file == $options['filename'] || $file == 'xx.' . $options['filename'] || array_search($options['langPath'] . DS . 'chk.' . $file, $files)) {
                             continue;
                         }
                         // otherwise grab the file content
                         if ($content = file_get_contents($options['langPath'] . DS . $file)) {
                             // parse the changed strings
                             $new_content = strtr($content, $changedStrings);
                             // check for changes then write to the file
                             if ($new_content != $content) {
                                 if (JFile::write($options['langPath'] . DS . $file, trim($new_content))) {
                                     $writeFiles[$write++] = $file;
                                 }
                             }
                         }
                     }
                 }
                 // report
                 if ($write) {
                     $mainframe->enqueueMessage(sprintf(JText::_('Global String Change'), $write, implode('; ', $writeFiles)));
                 }
             }
         }
     }
     // 1: checkin when we are saving (this will redirect also)
     // 2: call the html when we are editing or applying (and checkout existing files)
     if ($options['task'] == 'save_language') {
         Language_manager::multitask('checkin', $options['filename'], 'language_files', false);
     } else {
         Language_manager_html::Show_edit($editData, $editMeta, $options);
         if (!$options['newprocess']) {
             Language_manager::multitask('checkout', $options['filename'], false, false);
         }
     }
 }
             Language_manager::multitask($task = 'cancel');
             break;
         case 'checkin_language':
             Language_manager::multitask($task = 'checkin');
             break;
         case 'checkout_language':
             Language_manager::multitask($task = 'checkout');
             break;
         case 'language_publish':
             Language_manager::multitask($task = 'publish');
             break;
         case 'remove_language':
             Language_manager::multitask($task = 'remove');
             break;
         case 'language_unpublish':
             Language_manager::multitask($task = 'unpublish');
             break;
     }
     left_menu_footer();
     break;
     ##-- COMMON ----------------
 ##-- COMMON ----------------
 case 'cancel':
     cancel();
     break;
 case 'fixit':
     fixIt();
     break;
 case 'about':
     cacl_html::about(_COMMUNITY_ACL_COMP_NAME);
     break;