public static function generate(array $addOn, DevHelper_Config_Base $config, array $dataClass, array $info)
    {
        $className = self::getClassName($addOn, $config, $dataClass);
        $variableName = strtolower(substr($dataClass['camelCase'], 0, 1)) . substr($dataClass['camelCase'], 1);
        $modelClassName = DevHelper_Generator_Code_Model::getClassName($addOn, $config, $dataClass);
        $commentAutoGeneratedStart = DevHelper_Generator_File::COMMENT_AUTO_GENERATED_START;
        $commentAutoGeneratedEnd = DevHelper_Generator_File::COMMENT_AUTO_GENERATED_END;
        $dataWriterClassName = DevHelper_Generator_Code_DataWriter::getClassName($addOn, $config, $dataClass);
        $otherDataClassStuff = '';
        $filterParams = array();
        foreach ($dataClass['fields'] as $field) {
            if ($field['name'] != $dataClass['id_field']) {
                $filterParams[$field['name']] = $field['type'];
            }
        }
        $filterParams = DevHelper_Generator_File::varExport($filterParams, 2);
        $templateList = DevHelper_Generator_Template::getTemplateTitle($addOn, $config, $dataClass, $dataClass['name'] . '_list');
        $templateEdit = DevHelper_Generator_Template::getTemplateTitle($addOn, $config, $dataClass, $dataClass['name'] . '_edit');
        $templateDelete = DevHelper_Generator_Template::getTemplateTitle($addOn, $config, $dataClass, $dataClass['name'] . '_delete');
        $viewListClassName = self::getViewClassName($addOn, $config, $dataClass, 'list');
        $viewEditClassName = self::getViewClassName($addOn, $config, $dataClass, 'edit');
        $viewDeleteClassName = self::getViewClassName($addOn, $config, $dataClass, 'delete');
        // create the phrases
        $phraseClassName = DevHelper_Generator_Phrase::getPhraseName($addOn, $config, $dataClass, $dataClass['name']);
        $phraseAdd = DevHelper_Generator_Phrase::getPhraseName($addOn, $config, $dataClass, $dataClass['name'] . '_add');
        $phraseEdit = DevHelper_Generator_Phrase::getPhraseName($addOn, $config, $dataClass, $dataClass['name'] . '_edit');
        $phraseDelete = DevHelper_Generator_Phrase::getPhraseName($addOn, $config, $dataClass, $dataClass['name'] . '_delete');
        $phraseSave = DevHelper_Generator_Phrase::getPhraseName($addOn, $config, $dataClass, $dataClass['name'] . '_save');
        $phraseConfirmDeletion = DevHelper_Generator_Phrase::getPhraseName($addOn, $config, $dataClass, $dataClass['name'] . '_confirm_deletion');
        $phrasePleaseConfirm = DevHelper_Generator_Phrase::getPhraseName($addOn, $config, $dataClass, $dataClass['name'] . '_please_confirm');
        $phraseNotFound = DevHelper_Generator_Phrase::getPhraseName($addOn, $config, $dataClass, $dataClass['name'] . '_not_found');
        $phraseNoResults = DevHelper_Generator_Phrase::getPhraseName($addOn, $config, $dataClass, $dataClass['name'] . '_no_results');
        DevHelper_Generator_Phrase::generatePhrase($addOn, $phraseClassName, $dataClass['camelCaseWSpace']);
        DevHelper_Generator_Phrase::generatePhrase($addOn, $phraseAdd, 'Add New ' . $dataClass['camelCaseWSpace']);
        DevHelper_Generator_Phrase::generatePhrase($addOn, $phraseEdit, 'Edit ' . $dataClass['camelCaseWSpace']);
        DevHelper_Generator_Phrase::generatePhrase($addOn, $phraseDelete, 'Delete ' . $dataClass['camelCaseWSpace']);
        DevHelper_Generator_Phrase::generatePhrase($addOn, $phraseSave, 'Save ' . $dataClass['camelCaseWSpace']);
        DevHelper_Generator_Phrase::generatePhrase($addOn, $phraseConfirmDeletion, 'Confirm Deletion of ' . $dataClass['camelCaseWSpace']);
        DevHelper_Generator_Phrase::generatePhrase($addOn, $phrasePleaseConfirm, 'Please confirm that you want to delete the following ' . $dataClass['camelCaseWSpace']);
        DevHelper_Generator_Phrase::generatePhrase($addOn, $phraseNotFound, 'The requested ' . $dataClass['camelCaseWSpace'] . ' could not be found');
        DevHelper_Generator_Phrase::generatePhrase($addOn, $phraseNoResults, 'No clues of ' . $dataClass['camelCaseWSpace'] . ' at this moment...');
        // finished creating pharses
        // create the templates
        $templateListTemplate = <<<EOF
<xen:title>{xen:phrase {$phraseClassName}}</xen:title>

<xen:topctrl>
\t<a href="{xen:adminlink '{$info['routePrefix']}/add'}" class="button" accesskey="a">+ {xen:phrase {$phraseAdd}}</a>
</xen:topctrl>

<xen:require css="filter_list.css" />
<xen:require js="js/xenforo/filter_list.js" />

<xen:form action="{xen:adminlink '{$info['routePrefix']}'}" class="section">
\t<xen:if is="{\$all{$dataClass['camelCase']}}">
\t\t<h2 class="subHeading">
\t\t\t<link rel="xenforo_template" type="text/html" href="filter_list_controls.html" />
\t\t\t{xen:phrase {$phraseClassName}}
\t\t</h2>
\t
\t\t<ol class="FilterList Scrollable">
\t\t\t<xen:foreach loop="\$all{$dataClass['camelCase']}" value="\${$variableName}">
\t\t\t\t<xen:listitem
\t\t\t\t\tid="{\${$variableName}.{$dataClass['id_field']}}"
\t\t\t\t\thref="{xen:adminlink '{$info['routePrefix']}/edit', \${$variableName}}"
\t\t\t\t\tlabel="{\${$variableName}.{$dataClass['title_field']}}"
\t\t\t\t\tdelete="{xen:adminlink '{$info['routePrefix']}/delete', \${$variableName}}" />
\t\t\t</xen:foreach>
\t\t</ol>
\t
\t\t<p class="sectionFooter">{xen:phrase showing_x_of_y_items, 'count=<span class="FilterListCount">{xen:count \$all{$dataClass['camelCase']}}</span>', 'total={xen:count \$all{$dataClass['camelCase']}}'}</p>
\t<xen:else />
\t\t<div class="noResults">{xen:phrase {$phraseNoResults}}</div>
\t</xen:if>
</xen:form>
EOF;
        DevHelper_Generator_Template::generateAdminTemplate($addOn, $templateList, $templateListTemplate);
        // finished template_list
        $templateEditFields = '';
        foreach ($dataClass['fields'] as $field) {
            if ($field['name'] == $dataClass['id_field']) {
                continue;
            }
            if ($field['name'] == $dataClass['title_field']) {
                $fieldPhraseName = DevHelper_Generator_Phrase::generatePhraseAutoCamelCaseStyle($addOn, $config, $dataClass, $field['name']);
                $templateEditFields .= <<<EOF

\t<xen:textboxunit label="{xen:phrase {$fieldPhraseName}}:" name="{$field['name']}" value="{\${$variableName}.{$field['name']}}" data-liveTitleTemplate="{xen:if {\${$variableName}.{$dataClass['id_field']}},
\t\t'{xen:phrase {$phraseEdit}}: <em>%s</em>',
\t\t'{xen:phrase {$phraseAdd}}: <em>%s</em>'}" />
EOF;
                continue;
            }
            if (substr($field['name'], -3) == '_id') {
                // link to another dataClass?
                $other = substr($field['name'], 0, -3);
                if ($config->checkDataClassExists($other)) {
                    // yeah!
                    $otherDataClass = $config->getDataClass($other);
                    $fieldPhraseName = DevHelper_Generator_Phrase::generatePhraseAutoCamelCaseStyle($addOn, $config, $otherDataClass, $otherDataClass['name']);
                    $templateEditFields .= <<<EOF

\t<xen:selectunit label="{xen:phrase {$fieldPhraseName}}:" name="{$field['name']}" value="{\${$variableName}.{$field['name']}}">
\t\t<xen:option value="">&nbsp;</xen:option>
\t\t<xen:options source="\$all{$otherDataClass['camelCase']}" />
\t</xen:selectunit>
EOF;
                    $otherDataClassModelClassName = DevHelper_Generator_Code_Model::getClassName($addOn, $config, $otherDataClass);
                    $otherDataClassStuff .= <<<EOF
'all{$otherDataClass['camelCase']}' => \$this->getModelFromCache('{$otherDataClassModelClassName}')->getList(),
EOF;
                    continue;
                }
            }
            // special case with display_order
            if ($field['name'] == 'display_order') {
                $fieldPhraseName = DevHelper_Generator_Phrase::generatePhraseAutoCamelCaseStyle($addOn, $config, $dataClass, $field['name']);
                $templateEditFields .= <<<EOF

\t<xen:spinboxunit label="{xen:phrase {$fieldPhraseName}}:" name="{$field['name']}" value="{\${$variableName}.{$field['name']}}" />
EOF;
                continue;
            }
            $fieldPhraseName = DevHelper_Generator_Phrase::generatePhraseAutoCamelCaseStyle($addOn, $config, $dataClass, $field['name']);
            $extra = '';
            if ($field['type'] == XenForo_DataWriter::TYPE_STRING and (empty($field['length']) or $field['length'] > 255)) {
                $extra .= ' rows="5"';
            }
            $templateEditFields .= <<<EOF

\t<xen:textboxunit label="{xen:phrase {$fieldPhraseName}}:" name="{$field['name']}" value="{\${$variableName}.{$field['name']}}" {$extra}/>
EOF;
        }
        $templateEditTemplate = <<<EOF
<xen:title>{xen:if '{\${$variableName}.{$dataClass['id_field']}}', '{xen:phrase {$phraseEdit}}', '{xen:phrase {$phraseAdd}}'}</xen:title>

<xen:form action="{xen:adminlink '{$info['routePrefix']}/save'}" class="AutoValidator" data-redirect="yes">

\t{$templateEditFields}

\t<xen:submitunit save="{xen:phrase {$phraseSave}}">
\t\t<input type="button" name="delete" value="{xen:phrase {$phraseDelete}}"
\t\t\taccesskey="d" class="button OverlayTrigger"
\t\t\tdata-href="{xen:adminlink '{$info['routePrefix']}/delete', \${$variableName}}"
\t\t\t{xen:if '!{\${$variableName}.{$dataClass['id_field']}}', 'style="display: none"'}
\t\t/>
\t</xen:submitunit>
\t
\t<input type="hidden" name="{$dataClass['id_field']}" value="{\${$variableName}.{$dataClass['id_field']}}" />
</xen:form>
EOF;
        DevHelper_Generator_Template::generateAdminTemplate($addOn, $templateEdit, $templateEditTemplate);
        // finished template_edit
        $templateDeleteTemplate = <<<EOF
<xen:title>{xen:phrase {$phraseConfirmDeletion}}: {\${$variableName}.{$dataClass['title_field']}}</xen:title>
<xen:h1>{xen:phrase {$phraseConfirmDeletion}}</xen:h1>

<xen:navigation>
\t<xen:breadcrumb href="{xen:adminlink '{$info['routePrefix']}/edit', \${$variableName}}">{\${$variableName}.{$dataClass['title_field']}}</xen:breadcrumb>
</xen:navigation>

<xen:require css="delete_confirmation.css" />

<xen:form action="{xen:adminlink '{$info['routePrefix']}/delete', \${$variableName}}" class="deleteConfirmForm formOverlay">

\t<p>{xen:phrase {$phrasePleaseConfirm}}:</p>
\t<strong><a href="{xen:adminlink '{$info['routePrefix']}/edit', \${$variableName}}">{\${$variableName}.{$dataClass['title_field']}}</a></strong>

\t<xen:submitunit save="{xen:phrase {$phraseDelete}}" />
\t
\t<input type="hidden" name="_xfConfirm" value="1" />
</xen:form>
EOF;
        DevHelper_Generator_Template::generateAdminTemplate($addOn, $templateDelete, $templateDeleteTemplate);
        // finished creating our templates
        $contents = <<<EOF
<?php
class {$info['controller']} extends XenForo_ControllerAdmin_Abstract {

\t{$commentAutoGeneratedStart}

\tpublic function actionIndex() {
\t\t\$model = \$this->_get{$dataClass['camelCase']}Model();
\t\t\$all{$dataClass['camelCase']} = \$model->getAll{$dataClass['camelCase']}();
\t\t
\t\t\$viewParams = array(
\t\t\t'all{$dataClass['camelCase']}' => \$all{$dataClass['camelCase']}
\t\t);
\t\t
\t\treturn \$this->responseView('{$viewListClassName}', '{$templateList}', \$viewParams);
\t}
\t
\tpublic function actionAdd() {
\t\t\$viewParams = array(
\t\t\t'{$variableName}' => array(),
\t\t\t{$otherDataClassStuff}
\t\t);
\t\t
\t\treturn \$this->responseView('{$viewEditClassName}', '{$templateEdit}', \$viewParams);
\t}
\t
\tpublic function actionEdit() {
\t\t\$id = \$this->_input->filterSingle('{$dataClass['id_field']}', XenForo_Input::UINT);
\t\t\${$variableName} = \$this->_get{$dataClass['camelCase']}OrError(\$id);
\t\t
\t\t\$viewParams = array(
\t\t\t'{$variableName}' => \${$variableName},
\t\t\t{$otherDataClassStuff}
\t\t);
\t\t
\t\treturn \$this->responseView('{$viewEditClassName}', '{$templateEdit}', \$viewParams);
\t}
\t
\tpublic function actionSave() {
\t\t\$this->_assertPostOnly();
\t\t
\t\t\$id = \$this->_input->filterSingle('{$dataClass['id_field']}', XenForo_Input::UINT);

\t\t\$dwInput = \$this->_input->filter({$filterParams});
\t\t
\t\t\$dw = \$this->_get{$dataClass['camelCase']}DataWriter();
\t\tif (\$id) {
\t\t\t\$dw->setExistingData(\$id);
\t\t}
\t\t\$dw->bulkSet(\$dwInput);
\t\t\$dw->save();

\t\treturn \$this->responseRedirect(
\t\t\tXenForo_ControllerResponse_Redirect::SUCCESS,
\t\t\tXenForo_Link::buildAdminLink('{$info['routePrefix']}')
\t\t);
\t}
\t
\tpublic function actionDelete() {
\t\t\$id = \$this->_input->filterSingle('{$dataClass['id_field']}', XenForo_Input::UINT);
\t\t\${$variableName} = \$this->_get{$dataClass['camelCase']}OrError(\$id);
\t\t
\t\tif (\$this->isConfirmedPost()) {
\t\t\t\$dw = \$this->_get{$dataClass['camelCase']}DataWriter();
\t\t\t\$dw->setExistingData(\$id);
\t\t\t\$dw->delete();

\t\t\treturn \$this->responseRedirect(
\t\t\t\tXenForo_ControllerResponse_Redirect::SUCCESS,
\t\t\t\tXenForo_Link::buildAdminLink('{$info['routePrefix']}')
\t\t\t);
\t\t} else {
\t\t\t\$viewParams = array(
\t\t\t\t'{$variableName}' => \${$variableName}
\t\t\t);

\t\t\treturn \$this->responseView('{$viewDeleteClassName}', '{$templateDelete}', \$viewParams);
\t\t}
\t}
\t
\t
\tprotected function _get{$dataClass['camelCase']}OrError(\$id, array \$fetchOptions = array()) {
\t\t\$info = \$this->_get{$dataClass['camelCase']}Model()->get{$dataClass['camelCase']}ById(\$id, \$fetchOptions);
\t\t
\t\tif (empty(\$info)) {
\t\t\tthrow \$this->responseException(\$this->responseError(new XenForo_Phrase('{$phraseNotFound}'), 404));
\t\t}
\t\t
\t\treturn \$info;
\t}
\t
\tprotected function _get{$dataClass['camelCase']}Model() {
\t\treturn \$this->getModelFromCache('{$modelClassName}');
\t}
\t
\tprotected function _get{$dataClass['camelCase']}DataWriter() {
\t\treturn XenForo_DataWriter::create('{$dataWriterClassName}');
\t}

\t{$commentAutoGeneratedEnd}
}
EOF;
        return array($className, $contents);
    }
 protected function _getTemplateTitle($suffix)
 {
     return DevHelper_Generator_Template::getTemplateTitle($this->_addOn, $this->_config, $this->_dataClass, $this->_dataClass['name'] . $suffix);
 }