public function saveAction()
 {
     $app_id = $this->getAppId();
     $theme_id = waRequest::get('theme_id');
     $file = waRequest::get('file');
     $errors = null;
     $path = wa()->getDataPath('themes', true, $app_id, false);
     $this->checkAccess($path);
     // copy original theme
     $theme = new waTheme($theme_id, $app_id);
     if ($theme['type'] == waTheme::ORIGINAL) {
         $theme->copy();
     }
     // create file
     if (!$file) {
         // parent
         if (waRequest::post('type')) {
             $file = waRequest::post('parent');
             $theme->addFile($file, '', array('parent' => 1));
         } else {
             $file = waRequest::post('file');
             if ($this->checkFile($file, $errors)) {
                 $theme->addFile($file, waRequest::post('description'));
             }
         }
         if (!$errors) {
             if (!$theme->save()) {
                 $errors = _ws('Insufficient file access permissions to save theme settings');
             } else {
                 $this->logAction('template_add', $file);
             }
         }
     } else {
         if (waRequest::post('file') && $file != waRequest::post('file')) {
             if (!$this->checkFile(waRequest::post('file'), $errors)) {
                 $this->displayJson(array(), $errors);
                 return;
             }
             $theme->removeFile($file);
             $file = waRequest::post('file');
             if (!$theme->addFile($file, waRequest::post('description'))->save()) {
                 $errors = _ws('Insufficient file access permissions to save theme settings');
             } else {
                 $this->logAction('template_edit', $file);
             }
         } else {
             $f = $theme->getFile($file);
             if (!empty($theme['parent_theme_id']) && $f['parent']) {
                 $theme = new waTheme($theme['parent_theme_id']);
                 if ($theme['type'] == waTheme::ORIGINAL) {
                     $theme->copy();
                 }
             }
             if (!$theme->changeFile($file, waRequest::post('description'))) {
                 $errors = _ws('Insufficient file access permissions to save theme settings');
             } else {
                 $this->logAction('template_edit', $file);
             }
         }
         @touch($theme->getPath() . '/' . waTheme::PATH);
     }
     $response = array();
     if ($file && !$errors) {
         // update mtime of theme.xml
         @touch($path);
         $response['id'] = $file;
         switch ($ext = waFiles::extension($file)) {
             case 'css':
             case 'js':
                 $response['type'] = $ext;
                 break;
             default:
                 $response['type'] = '';
         }
         $response['theme'] = $theme_id;
         // if not parent
         if (!waRequest::post('type')) {
             $content = waRequest::post('content');
             $file_path = $theme->getPath() . '/' . $file;
             if (!file_exists($file_path) || is_writable($file_path)) {
                 if ($content || file_exists($file_path)) {
                     $r = @file_put_contents($file_path, $content);
                     if ($r !== false) {
                         $r = true;
                         if (in_array($ext, array('css', 'js'))) {
                             $theme['edition'] = true;
                             $theme->save();
                         }
                     }
                 } else {
                     $r = @touch($file_path);
                 }
             } else {
                 $r = false;
             }
             if (!$r) {
                 $errors = _ws('Insufficient access permissions to save the file') . ' ' . $file_path;
             }
         } else {
             $response['inherit'] = 1;
         }
     }
     $this->displayJson($response, $errors);
 }
    protected function create($app_id, $path, $params = array())
    {
        $report = '';
        if (!file_exists($path)) {
            $path .= '/';
            mkdir($path);
            mkdir($path . 'css');
            touch($path . 'css/' . $app_id . '.css');
            mkdir($path . 'js');
            touch($path . 'js/' . $app_id . '.js');
            mkdir($path . 'img');
            // lib
            mkdir($path . 'lib');
            waFiles::protect($path . 'lib');
            mkdir($path . 'lib/actions');
            // backend controller
            mkdir($path . 'lib/actions/backend');
            // api
            if (isset($params['api'])) {
                mkdir($path . 'lib/api');
                if ($params['api'] !== true) {
                    mkdir($path . 'lib/api/' . $params['api']);
                } else {
                    mkdir($path . 'lib/api/v1');
                }
            }
            // cli
            if (isset($params['cli'])) {
                mkdir($path . 'lib/cli');
            }
            mkdir($path . 'lib/classes');
            mkdir($path . 'lib/models');
            // config
            mkdir($path . 'lib/config');
            // app description
            $app = array('name' => empty($params['name']) ? ucfirst($app_id) : $params['name'], 'icon' => 'img/' . $app_id . '.gif', 'version' => $version = empty($params['version']) ? '0.1' : $params['version'], 'vendor' => $vendor = empty($params['vendor']) ? '--' : $params['vendor']);
            if (isset($params['frontend'])) {
                $app['frontend'] = true;
                if (isset($params['themes'])) {
                    $app['themes'] = true;
                }
                $routing = array('*' => 'frontend');
                waUtils::varExportToFile($routing, $path . 'lib/config/routing.php');
                // frontend controller
                mkdir($path . 'lib/actions/frontend');
            }
            // plugins
            if (isset($params['plugins'])) {
                $app['plugins'] = true;
                mkdir($path . 'plugins');
            }
            waUtils::varExportToFile($app, $path . 'lib/config/app.php');
            // templates
            mkdir($path . 'templates');
            waFiles::protect($path . 'templates');
            mkdir($path . 'templates/actions');
            mkdir($path . 'templates/actions/backend');
            // backend template
            if (isset($params['frontend'])) {
                // frontend template
                mkdir($path . 'templates/actions/frontend');
            }
            // locale
            mkdir($path . 'locale');
            waFiles::protect($path . 'locale');
            if (isset($params['frontend']) && isset($params['themes'])) {
                // themes
                mkdir($path . 'themes');
                mkdir($path . 'themes/default');
                $theme = new waTheme('default', $app_id, true);
                $theme->name = 'Default theme';
                $theme->description = 'Auto generated default theme';
                $theme->vendor = $vendor;
                $theme->system = 1;
                $theme->addFile('index.html', 'Frontend index file');
                touch($path . 'themes/default/index.html');
                $theme->addFile('default.css', 'Frontend CSS file');
                touch($path . 'themes/default/default.css');
                $theme->version = $version;
                $theme->save();
                waFiles::move($theme->path . '/theme.xml', $path . 'themes/default/theme.xml');
            }
            $report .= <<<REPORT
App with id "{$app_id}" created!

Useful commands:
    #generate app's database description file db.php
    php wa.php generateDb {$app_id}

    #generate app's locale files
    php wa-system/locale/locale.php {$app_id}
REPORT;
            if (isset($params['plugins'])) {
                $report .= "\n\n" . <<<REPORT
    #create a plugin with specified 'plugin_id' for your app
    php wa.php createPlugin {$app_id} plugin_id
REPORT;
            }
            //TODO add hint about compress command
        } else {
            $report .= <<<REPORT
App with id "{$app_id}" already exists.
REPORT;
        }
        print $report . "\n";
    }
 protected function create($app_id, $path, $params = array())
 {
     if (!file_exists($path)) {
         $path .= '/';
         mkdir($path);
         mkdir($path . 'css');
         touch($path . 'css/' . $app_id . '.css');
         mkdir($path . 'js');
         touch($path . 'js/' . $app_id . '.js');
         mkdir($path . 'img');
         // lib
         mkdir($path . 'lib');
         waFiles::protect($path . 'lib');
         mkdir($path . 'lib/actions');
         // backend controller
         mkdir($path . 'lib/actions/backend');
         // api
         if (isset($params['api'])) {
             mkdir($path . 'lib/api');
             if ($params['api'] !== true) {
                 mkdir($path . 'lib/api/' . $params['api']);
             }
         }
         // cli
         if (isset($params['cli'])) {
             mkdir($path . 'lib/cli');
         }
         mkdir($path . 'lib/classes');
         mkdir($path . 'lib/models');
         // config
         mkdir($path . 'lib/config');
         // app description
         $app = array('name' => empty($params['name']) ? ucfirst($app_id) : $params['name'], 'icon' => 'img/' . $app_id . '.gif', 'version' => $version = empty($params['version']) ? '0.1' : $params['version']);
         if (isset($params['frontend'])) {
             $app['frontend'] = true;
             if (isset($params['themes'])) {
                 $app['themes'] = true;
             }
             $routing = array('*' => 'frontend');
             waUtils::varExportToFile($routing, $path . 'lib/config/routing.php');
             // frontend controller
             mkdir($path . 'lib/actions/frontend');
         }
         // plugins
         if (isset($params['plugins'])) {
             $app['plugins'] = true;
             mkdir($path . 'plugins');
         }
         waUtils::varExportToFile($app, $path . 'lib/config/app.php');
         // templates
         mkdir($path . 'templates');
         waFiles::protect($path . 'templates');
         mkdir($path . 'templates/actions');
         mkdir($path . 'templates/actions/backend');
         // backend template
         if (isset($params['frontend'])) {
             // frontend template
             mkdir($path . 'templates/actions/frontend');
         }
         // locale
         mkdir($path . 'locale');
         if (isset($params['frontend']) && isset($params['themes'])) {
             // themes
             mkdir($path . 'themes');
             mkdir($path . 'themes/default');
             $theme = new waTheme('default', $app_id, true);
             $theme->name = 'Default theme';
             $theme->description = 'Auto generated default theme';
             $theme->system = 1;
             $theme->addFile('index.html', 'Frontend index file');
             touch($path . 'themes/default/index.html');
             $theme->addFile('default.css', 'Frontend CSS file');
             touch($path . 'themes/default/default.css');
             $theme->version = $version;
             $theme->save();
         }
         print "App with id {$app_id} created";
     } else {
         print "App with id {$app_id} already exists";
     }
 }
    protected function create($params = array())
    {
        //TODO layout|ajax|simple mode
        $structure = array("css/{$this->app_id}.css", "js/{$this->app_id}.js", "img/", "img/{$this->app_id}48.png" => $this->root_path . 'wa-content/img/dummy-app-icon-48.png', "img/{$this->app_id}96.png" => $this->root_path . 'wa-content/img/dummy-app-icon-96.png', "lib/", "lib/actions/backend/", "lib/actions/backend/{$this->app_id}Backend.action.php" => $this->getActionCode(), "templates/actions/backend/Backend.html" => $this->getDefaultTemplate(), "lib/classes/", "lib/models/", "lib/config/", "locale/");
        $features = array_map('trim', preg_split('@[,\\s]+@', ifset($params['features'], $this->getDefaults('features'))));
        // api
        if (in_array('api', $features, true)) {
            $structure = array_merge($structure, array("lib/api/v1/"));
        }
        if (in_array('cli', $features, true)) {
            $structure = array_merge($structure, array("lib/cli/", "lib/cli/{$this->app_id}Example.cli.php" => $this->getCliController()));
        }
        $protect = array('lib', 'templates');
        // app description
        $app = array('name' => empty($params['name']) ? ucfirst($this->app_id) : $params['name'], 'icon' => array(48 => "img/{$this->app_id}48.png", 96 => "img/{$this->app_id}96.png"), 'version' => ifempty($params['version'], $this->getDefaults('version')), 'vendor' => ifempty($params['vendor'], $this->getDefaults('vendor')));
        if (isset($params['frontend'])) {
            $app['frontend'] = true;
            if ($params['frontend'] == 'themes') {
                $app['themes'] = true;
            }
            $routing = array('*' => 'frontend');
            $structure['lib/config/routing.php'] = $routing;
            $structure = array_merge($structure, array('lib/actions/frontend/', "lib/actions/frontend/{$this->app_id}Frontend.action.php" => $this->getActionCode('default', false, $app)));
            if (!empty($app['themes'])) {
                $structure = array_merge($structure, array('themes/.htaccess' => '
<FilesMatch "\\.(php\\d*|html?|xml)$">
    Deny from all
</FilesMatch>
', 'themes/default/index.html' => $this->getFrontendTemplate(), 'themes/default/css/default.css'));
            } else {
                $structure = array_merge($structure, array("templates/actions/frontend/Frontend.html" => $this->getFrontendTemplate(), "css/frontend/{$this->app_id}.css"));
            }
        }
        if (isset($params['plugins'])) {
            $structure = array_merge($structure, array("plugins/"));
            $app['plugins'] = true;
        }
        $structure['lib/config/app.php'] = $app;
        $this->createStructure($structure);
        $this->protect($protect);
        if (!empty($app['themes'])) {
            waFiles::delete(wa()->getDataPath('themes/default', true, $this->app_id));
            $theme = new waTheme('default', $this->app_id, true);
            $theme->name = 'Default theme';
            $theme->description = 'Auto generated default theme';
            $theme->vendor = $app['vendor'];
            $theme->version = $app['version'];
            $theme->addFile('index.html', 'Frontend index file');
            $theme->addFile('css/default.css', 'Frontend CSS file');
            $theme->save();
            waFiles::move($theme->path . '/theme.xml', $this->path . 'themes/default/theme.xml');
        }
        if (!isset($params['disable'])) {
            $this->installApp();
            $errors = $this->flushCache();
            if ($errors) {
                print "Error during delete cache files:\n\t" . implode("\n\t", $errors) . "\n";
            }
        }
        return $app;
    }