Repository: Alignak-monitoring-contrib/alignak-app (language: python)

Issue:
Review install mode
Currently, App manage a lot of thing to ensure installation is correct and ready to run.

But she should check earlier the user folder, create it if does not exists and copy required files:

* Python files who manage installation should be placed in another package.
* App should check folders and configuration files on `--start` and `--install`
* App should create folders, daemon file and configuration files on `--install`

Then App can try to connect to Backend !
Review install mode
Currently, App manage a lot of thing to ensure installation is correct and ready to run.

But she should check earlier the user folder, create it if does not exists and copy required files:

* Python files who manage installation should be placed in another package.
* App should check folders and configuration files on `--start` and `--install`
* App should create folders, daemon file and configuration files on `--install`

Then App can try to connect to Backend !


Discussion / hints:

Fix patch:
diff --git a/.travis.yml b/.travis.yml
index aa907eb..6550bc1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,9 +5,11 @@ python:
   - "3.6"
 
 before_script:
-  - "export DISPLAY=:99.0"
-  - "sh -e /etc/init.d/xvfb start"
+  - export DISPLAY=:99.0
+  - sh -e /etc/init.d/xvfb start
   - sleep 3
+  # Export ALIGNAKAPP_APP_DIR, only needed for Travis.
+  - export ALIGNAKAPP_APP_DIR=$HOME/.local/alignak_app
 
 install:
   - ./test/setup_test.sh
diff --git a/alignak_app/__init__.py b/alignak_app/__init__.py
index bbd655c..279afce 100644
--- a/alignak_app/__init__.py
+++ b/alignak_app/__init__.py
@@ -41,6 +41,15 @@
     * The :class:`Utils <alignak_app.utils>` package contains settings, logs, installation,...
     * The :class:`Locales <alignak_app.locales>` package contains translations.
 
+    Alignak-app will use a system of :class:`Installer <alignak_app.utils.installer.Installer>`
+    who use **environment variables** to run:
+
+    * ``ALIGNAKAPP_USR_DIR``: contains settings of user (**write rights**)
+    * ``ALIGNAKAPP_LOG_DIR``: contains log files of App (**write rights**)
+    * ``ALIGNAKAPP_APP_DIR``: contains binaries of App (images, css, languages) (**read rights**)
+
+    The :class:`Login <alignak_app.qobjects.login.login.LoginQDialog>` manage user login if needed.
+
 """
 
 
diff --git a/alignak_app/app.py b/alignak_app/app.py
index 7e14d1a..44b85e2 100644
--- a/alignak_app/app.py
+++ b/alignak_app/app.py
@@ -24,8 +24,10 @@
     ~~~
     App manages the creation of QObjects for the whole application:
 
-    * Creation of QObject for App Main (QMainWindow)
-    * Creation of QProgressbar until the Data Manager is ready
+    * Creation of :class:`AppProgressBar <alignak_app.app.AppProgressBar>` until the Data Manager is
+      ready
+    * Creation of :class:`AppQMainWindow <alignak_app.qobjects.app_main.AppQMainWindow>`
+    * Creation of standard python objects (settings, css, localization)
 """
 
 import os
@@ -146,12 +148,14 @@ def start(self, username=None, password=None):
 
         logger.info('\n')
         logger.info('----- Alignak-App START -----')
-        logger.info('- Environment variables:')
-        logger.info('[ALIGNAKAPP_LOG_DIR] = "%s"', os.environ['ALIGNAKAPP_LOG_DIR'])
-        logger.info('[ALIGNAKAPP_USR_CFG] = "%s"', os.environ['ALIGNAKAPP_USR_CFG'])
-        logger.info('[ALIGNAKAPP_APP_CFG] = "%s"', os.environ['ALIGNAKAPP_APP_CFG'])
-        logger.info('- App logging debug: %s', settings.get_config('Log', 'debug', boolean=True))
-        logger.info('- Alignak Backend  : %s', settings.get_config('Alignak', 'backend'))
+        logger.info('- Running Version : "%s"', __version__)
+        logger.info('- Alignak-App Env :')
+        logger.info('[ALIGNAKAPP_APP_DIR] = %s', os.environ['ALIGNAKAPP_APP_DIR'])
+        logger.info('[ALIGNAKAPP_USR_DIR] = %s', os.environ['ALIGNAKAPP_USR_DIR'])
+        logger.info('[ALIGNAKAPP_LOG_DIR] = %s', os.environ['ALIGNAKAPP_LOG_DIR'])
+        logger.info('- Config File     : %s', settings.settings['settings'])
+        logger.info('- Debug Activate  : %s', settings.get_config('Log', 'debug', boolean=True))
+        logger.info('- Alignak Backend : %s', settings.get_config('Alignak', 'backend'))
 
         app = QApplication(sys.argv)
         app.setQuitOnLastWindowClosed(False)
diff --git a/alignak_app/qobjects/panel/history.py b/alignak_app/qobjects/panel/history.py
index 828d84b..5cdecbb 100644
--- a/alignak_app/qobjects/panel/history.py
+++ b/alignak_app/qobjects/panel/history.py
@@ -118,9 +118,9 @@ def get_history_widget_model(history_event, hostname):
         event_name = ''
         if 'service_name' in history_event:
             if history_event['service_name']:
-                event_name = history_event['service_name'].capitalize()
+                event_name = _('Service: %s') % history_event['service_name'].capitalize()
         if not event_name:
-            event_name = hostname.capitalize()
+            event_name = _('Host: %s') % hostname.capitalize()
 
         icon_name = History.get_history_icon_name_from_message(
             history_event['message'], history_event['type']
diff --git a/alignak_app/utils/config.py b/alignak_app/utils/config.py
index db68aab..a7436bc 100644
--- a/alignak_app/utils/config.py
+++ b/alignak_app/utils/config.py
@@ -27,23 +27,17 @@
     * ``settings.cfg``: contains configurations of Alignak-app
     * ``images.ini``: contains all images names
     * ``style.css``: contains css of Alignak-app
-
-    The following environment variables are managed in this file:
-
-    * ``ALIGNAKAPP_USR_CFG``: folder that contains settings of user (settings.cfg)
-    * ``ALIGNAKAPP_APP_CFG``: folder that contains binaries of ALignak-app (images, css, languages)
 """
 
 import os
-import sys
 import webbrowser
 
 from logging import getLogger
 
 import configparser
-from configparser import NoOptionError, NoSectionError, DuplicateOptionError, DuplicateSectionError
+from configparser import NoOptionError, NoSectionError
 
-from alignak_app.utils.install import create_user_app_dir
+from alignak_app.utils.system import read_config_file
 
 logger = getLogger(__name__)
 
@@ -80,28 +74,15 @@ class Settings(object):
             'debug': True
         }
     }
-    # Defines configuration files
-    if 'win32' not in sys.platform:
-        config_dirs = [
-            '%s/.local/alignak_app' % os.environ['HOME'],
-            '/usr/local/alignak_app'
-        ]
-    else:
-        config_dirs = [
-            '%s\\Python\\alignak_app' % os.environ['APPDATA'],
-            '%s\\Alignak-app' % os.environ['PROGRAMFILES']
-        ]
 
     def __init__(self):
         self.app_config = configparser.ConfigParser(os.environ)
         self.img_config = configparser.ConfigParser()
-        self.user_cfg_dir = None
-        self.app_cfg_dir = None
+        self.css_style = ''
         self.settings = {
             'settings': '',
             'images': ''
         }
-        self.css_style = None
 
     def init_config(self):
         """
@@ -109,68 +90,11 @@ def init_config(self):
 
         """
 
-        def read_config_file(cfg_parser, filename):
-            """
-            Read configuration file and assign it to configParser object
-
-            :param cfg_parser: configparser object
-            :type cfg_parser: configparser.ConfigParser
-            :param filename: name of file to read
-            :type filename: str
-            :return: corresponding filename if read is success
-            :rtype: str
-            """
+        settings_cfgs = '%s/settings.cfg' % os.environ['ALIGNAKAPP_USR_DIR']
+        images_ini = '%s/images.ini' % os.environ['ALIGNAKAPP_APP_DIR']
 
-            try:
-                cfg_file = cfg_parser.read(filename)
-                if cfg_file:
-                    return cfg_file[0]
-            except (DuplicateOptionError, DuplicateSectionError) as d:  # pragma: no cover
-                logger.error('Duplicate Option/Section in file [%s] !', d)
-                sys.exit('Duplicate Option/Section in file [%s] !' % d)
-            except Exception as ex:  # pragma: no cover - not testable
-                logger.error('Configuration file is missing in [%s] !', ex)
-                sys.exit('Configuration file is missing in [%s] !' % ex)
-
-            return None
-
-        # Create available configurations files
-        available_cfg_files = {
-            'settings': [],
-            'images': []
-        }
-        for cfg_dir in self.config_dirs:
-            available_cfg_files['settings'].append('%s/settings.cfg' % cfg_dir)
-            available_cfg_files['images'].append('%s/images.ini' % cfg_dir)
-
-        # Sets fields with environment variables if they exists
-        if 'ALIGNAKAPP_USR_CFG' in os.environ:
-            self.user_cfg_dir = os.environ['ALIGNAKAPP_USR_CFG']
-        if 'ALIGNAKAPP_APP_CFG' in os.environ:
-            self.app_cfg_dir = os.environ['ALIGNAKAPP_APP_CFG']
-
-        # Read configuration files
-        logger.info('Reading configuration files...')
-        for f in available_cfg_files['settings']:
-            self.settings['settings'] = read_config_file(self.app_config, f)
-            if self.settings['settings']:
-                # Create a user directory and copy "settings.cfg" file if needed
-                self.settings['settings'] = create_user_app_dir(self.settings['settings'])
-                if not self.user_cfg_dir:
-                    self.user_cfg_dir = os.path.split(self.settings['settings'])[0]
-                break
-        for f in available_cfg_files['images']:
-            self.settings['images'] = read_config_file(self.img_config, f)
-            if self.settings['images']:
-                if not self.app_cfg_dir:
-                    self.app_cfg_dir = os.path.split(self.settings['images'])[0]
-                break
-
-        # Sets the environment variables to make them accessible by App
-        if 'ALIGNAKAPP_USR_CFG' not in os.environ:
-            os.environ['ALIGNAKAPP_USR_CFG'] = self.user_cfg_dir
-        if 'ALIGNAKAPP_APP_CFG' not in os.environ:
-            os.environ['ALIGNAKAPP_APP_CFG'] = self.app_cfg_dir
+        self.settings['settings'] = read_config_file(self.app_config, settings_cfgs)
+        self.settings['images'] = read_config_file(self.img_config, images_ini)
 
     def get_config(self, section, option, boolean=False):
         """
@@ -233,8 +157,12 @@ def edit_setting_value(self, section, option, new_value):
                     data[data.index(d)] = option + ' = ' + new_value + '\n'
             # Setting the current configuration
             self.app_config.set(section, option, new_value)
-            with open(file_to_write, 'w') as new_config_file:
-                new_config_file.writelines(data)
+            try:
+                with open(file_to_write, 'w') as new_config_file:
+                    new_config_file.writelines(data)
+            except PermissionError as e:
+                print('Not permission to write inside [%s] !' % file_to_write)
+                exit(e)
 
         except NoOptionError as e:  # pragma: no cover
             logger.error('Can\'t set Option in configuration file : %s', e)
@@ -250,10 +178,11 @@ def get_image(self, name):
         """
 
         try:
-            return '%s/images/%s' % (self.app_cfg_dir, self.img_config.get('Images', name))
+            return '%s/images/%s' % \
+                   (os.environ['ALIGNAKAPP_APP_DIR'], self.img_config.get('Images', name))
         except (NoOptionError, NoSectionError) as e:
             logger.error('Image not found or not set in [images.ini] : %s', e)
-            return '%s/images/error.svg' % self.app_cfg_dir
+            return '%s/images/error.svg' % os.environ['ALIGNAKAPP_APP_DIR']
 
     def init_css(self):
         """
@@ -262,11 +191,11 @@ def init_css(self):
         """
 
         try:
-            css = open('%s/css/style.css' % self.app_cfg_dir)
+            css = open('%s/css/style.css' % os.environ['ALIGNAKAPP_APP_DIR'])
             self.css_style = css.read()
         except IOError as e:
             logger.error('CSS File is missing : %s', str(e))
-            self.css_style = ""
+            self.css_style = ''
 
 
 # Initialize Settings object
diff --git a/alignak_app/utils/install.py b/alignak_app/utils/install.py
deleted file mode 100644
index c232760..0000000
--- a/alignak_app/utils/install.py
+++ /dev/null
@@ -1,244 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2015-2018:
-#   Matthieu Estrada, ttamalfor@gmail.com
-#
-# This file is part of (AlignakApp).
-#
-# (AlignakApp) is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# (AlignakApp) is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with (AlignakApp).  If not, see <http://www.gnu.org/licenses/>.
-
-"""
-    Install
-    +++++++
-    Install manage installation folders and the daemon file creation
-"""
-
-import os
-import sys
-import stat
-import subprocess
-
-from alignak_app import __alignak_url__, __doc_url__, __version__, __releasenotes__, __application__
-
-
-def create_user_app_dir(cfg_file):
-    """
-    Create a user folder for App configuration file and log
-
-    :param cfg_file: file to copy if user has no rights
-    :type cfg_file: str
-    :return: return original file if user ha right, else the new file created
-    :rtype: str
-    """
-
-    # If the file exists, App add a sample file
-    if not os.path.isfile(cfg_file + '.sample'):
-        creation = subprocess.run(
-            ['cp', cfg_file, cfg_file + '.sample'],
-            stdout=subprocess.PIPE,
-            stderr=subprocess.STDOUT
-        )
-        try:
-            assert creation.returncode == 0
-        except AssertionError:
-            print("User folder creation: ", creation.stdout.decode('UTF-8'))
-
-    if not os.access(cfg_file, os.W_OK):
-        # Create Folder for user if does not exist
-        user_app_dir = '%s/.local/alignak_app' % os.environ['HOME']
-        if not os.path.exists(user_app_dir):
-            try:
-                os.makedirs(user_app_dir)
-            except (PermissionError, FileExistsError) as e:
-                print(e)
-                sys.exit('Can\'t create App directory for user in [%s] !' % user_app_dir)
-
-        # If file does not exist, App create it
-        dest_file = os.path.join(user_app_dir, os.path.split(cfg_file)[1])
-        if not os.path.isfile(dest_file):
-            creation = subprocess.run(
-                ['cp', cfg_file, dest_file],
-                stdout=subprocess.PIPE,
-                stderr=subprocess.STDOUT
-            )
-            try:
-                assert creation.returncode == 0
-            except AssertionError:
-                print("Copy of user configuration file: ", creation.stdout.decode('UTF-8'))
-
-        return dest_file
-    else:
-        return cfg_file
-
-
-def write_file(install_path, filename, text, *args):
-    """
-    Write file in system, make it executbale or add autocompletion to "rc" user file
-
-    :param install_path: path where to write
-    :type install_path: str
-    :param filename: name of file to write
-    :type filename: str
-    :param text: text to write inside filename
-    :type text: str
-    :param args: argument who define if executable or autocomplete
-    :type args: tuple
-    :return: 0 if success, else return error string
-    :rtype: int | str
-    """
-
-    file_to_write = os.path.join(install_path, filename)
-    returncode = '%s can\'t create following file: %s' % (__application__, file_to_write)
-
-    try:
-        with open(file_to_write, 'w') as cur_file:
-            cur_file.write(text)
-
-        if 'exec' in args:
-            print('Create/Update [%s]' % file_to_write)
-            # Make file executable
-            try:
-                st = os.stat(file_to_write)
-                os.chmod(file_to_write, st.st_mode | stat.S_IEXEC)
-                returncode = 0
-            except Exception as e:
-                returncode = '%s can\'t set permissions on daemon file: %s\n%s' % (
-                    __application__, file_to_write, str(e))
-
-        if 'autocomplete' in args:
-            # Add auto completion
-            user_rc = ''
-            for autocomplete_file in ['.bashrc', '.zshrc']:
-                if os.path.isfile('%s/%s' % (os.environ['HOME'], autocomplete_file)):
-                    user_rc = '%s/%s' % (os.environ['HOME'], autocomplete_file)
-                    print('Add autocompletion inside [%s]' % user_rc)
-                    break
-            autocompletion_text = '\n# Alignak-app completion:\n. %s' % file_to_write
-
-            try:
-                bashrc = open(user_rc, 'r')
-                if 'Alignak-app completion' not in bashrc.read():
-                    bashrc.close()
-                    with open(user_rc, 'a') as cur_rc_file:
-                        cur_rc_file.write(autocompletion_text)
-                else:
-                    bashrc.close()
-                returncode = 0
-            except Exception as w:
-                returncode = '%s can\'t add completion to your: %s\n%s' % (
-                    __application__, user_rc, str(w))
-    except Exception as w:
-        returncode = '%s can\'t create following file: %s\n%s' % (
-            __application__, file_to_write, str(w))
-
-    return returncode
-
-
-def check_return_code(returncode):
-    """
-    Check if returncode is equal to 0, else exit with error
-
-    :param returncode: returncode to check
-    :type returncode: int | str
-    :return: OK if code is equal to 0, else exit()
-    :rtype: str | None
-    """
-
-    if returncode == 0:
-        return 'OK'
-
-    return sys.exit('ERROR: %s' % returncode)
-
-
-def display_app_env():
-    """
-    Display current environment variables used by App
-
-    """
-
-    app_env_var = ['ALIGNAKAPP_APP_CFG', 'ALIGNAKAPP_USR_CFG', 'ALIGNAKAPP_LOG_DIR']
-
-    print('Use following variables:')
-    for env_var in app_env_var:
-        try:
-            print('- [%s] = %s' % (env_var, os.environ[env_var]))
-        except KeyError:
-            print('- [%s] = None' % env_var)
-    print('')
-
-
-def install_alignak_app(bin_file):
-    """
-    Install an "alignak-app" daemon for user
-
-    :param bin_file: python file "alignak-app.py" who have been launched
-    :type bin_file: str
-    """
-
-    if not os.path.isdir('%s/bin' % os.environ['HOME']):
-        try:
-            os.mkdir('%s/bin' % os.environ['HOME'])
-        except IOError as e:
-            print('%s fail to create bin directory!' % __application__)
-            sys.exit(e)
-
-    possible_paths = [
-        '%s/bin' % os.environ['HOME'], '/usr/local/bin', '/usr/sbin'
-    ]
-
-    install_path = ''
-    for path in possible_paths:
-        if path in os.environ['PATH'] and os.access(path, os.W_OK):
-            install_path = path
-
-    if install_path:
-        # Start installation
-        print('----------- Install -----------\nInstallation start...\n')
-        display_app_env()
-        daemon_name = 'alignak-app'
-        auto_name = 'alignak-app-auto'
-
-        # Create daemon bash file
-        bash_sample = '%s/bin-samples/%s.sample.sh' % (
-            os.environ['ALIGNAKAPP_APP_CFG'], daemon_name)
-        bash_file = open(bash_sample)
-        bash_format = bash_file.read() % (
-            daemon_name, bin_file, os.environ['ALIGNAKAPP_APP_CFG'],
-            os.environ['ALIGNAKAPP_USR_CFG'], os.environ['ALIGNAKAPP_LOG_DIR'], __version__,
-            __releasenotes__, __alignak_url__, __doc_url__,
-        )
-        bash_file.close()
-        status = check_return_code(
-            write_file(install_path, daemon_name, bash_format, 'exec')
-        )
-        print('Daemon file...%s' % status)
-
-        # Create autocomplete file
-        bash_auto_sample = \
-            '%s/bin-samples/%s.sample.sh' % (os.environ['ALIGNAKAPP_APP_CFG'], auto_name)
-        bash_auto_file = open(bash_auto_sample)
-        autocomplete_format = bash_auto_file.read() % (
-            os.path.join(install_path, daemon_name), daemon_name
-        )
-        bash_auto_file.close()
-        status = check_return_code(
-            write_file(install_path, auto_name, autocomplete_format, 'autocomplete')
-        )
-        print('Auto completion...%s\n' % status)
-
-        # Installation is done !
-        print('Installation is done ! You can run "%s" command !' % daemon_name)
-    else:
-        print('Please restart this script with a "root" user.')
diff --git a/alignak_app/utils/installer.py b/alignak_app/utils/installer.py
new file mode 100644
index 0000000..aabd0c1
--- /dev/null
+++ b/alignak_app/utils/installer.py
@@ -0,0 +1,276 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015-2018:
+#   Matthieu Estrada, ttamalfor@gmail.com
+#
+# This file is part of (AlignakApp).
+#
+# (AlignakApp) is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# (AlignakApp) is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with (AlignakApp).  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+    Installer
+    +++++++++
+    Installer check and manage installation of Alignak-app
+
+    * Check ``ALIGNAKAPP_APP_DIR``, ``ALIGNAKAPP_USR_DIR`` and ``ALIGNAKAPP_LOG_DIR``
+    * Check required files for application and user
+    * Install configuration and daemon files for user
+"""
+
+import os
+import sys
+
+from alignak_app import __project_url__, __doc_url__, __version__, __releasenotes__, __application__
+
+from alignak_app.utils.system import install_file, write_file, write_rc_file, mkdir, file_executable
+
+
+class Installer(object):
+    """
+        Class who create and check: folders, files and environment variables for Alignak-App
+    """
+
+    daemon_name = __application__.lower()
+    app_folder = __application__.lower().replace('-', '_')
+
+    if 'win32' in sys.platform:
+        install_folders = [
+            '%s\\Python\\%s' % (os.environ['APPDATA'], app_folder),
+            '%s\\Alignak-app' % os.environ['PROGRAMFILES']
+        ]
+    else:
+        install_folders = [
+            '%s/.local/%s/bin' % (os.environ['HOME'], app_folder),
+            '/usr/local/%s/bin' % app_folder
+        ]
+
+    states = {
+        True: 'OK',
+        False: 'Problem !'
+    }
+
+    def __init__(self):
+        self.app_dir = ''
+        self.usr_cfg = ''
+        self.log_dir = ''
+
+    def check_installation(self, mode='start'):
+        """
+        Check Alignak-app installation
+
+        """
+
+        self.init_environment()
+
+        check_folder = self.check_install_folders()
+        if 'install' in mode:
+            print('- Check installation folders: %s' % self.states[check_folder])
+
+        self.check_environment(mode)
+
+        if 'start' in mode:
+            self.check_user_installation()
+
+        check_files = self.check_install_files()
+        if 'install' in mode:
+            print('- Check installation files: %s' % self.states[check_files])
+
+    def check_install_folders(self):
+        """
+        Check Alignak-app folders
+
+        :return: if all folders are present
+        :rtype: bool
+        """
+
+        check_folders = True
+        if not self.app_dir:
+            for folder in self.install_folders:
+                if os.path.exists(folder):
+                    self.app_dir = folder.replace('/bin', '')
+
+            if not self.app_dir:
+                print('Alignak-App does not seem to be installed on your system.\n'
+                      'Thank you for reading the documentation: %s' % __doc_url__)
+                sys.exit(1)
+
+        if not self.usr_cfg:
+            if 'win32' in sys.platform:
+                self.usr_cfg = '%s\\Alignak-app' % os.environ['PROGRAMFILES']
+            else:
+                self.usr_cfg = '%s/.local/%s' % (os.environ['HOME'], self.app_folder)
+        if not self.log_dir:
+            if 'win32' in sys.platform:
+                self.log_dir = '%s\\Alignak-app' % os.environ['PROGRAMFILES']
+            else:
+                self.log_dir = '%s/.local/%s' % (os.environ['HOME'], self.app_folder)
+
+        if not os.path.exists(self.usr_cfg):
+            check_folders = mkdir(self.usr_cfg)
+        if not os.path.exists(self.log_dir):
+            check_folders = mkdir(self.log_dir)
+
+        return check_folders
+
+    def check_install_files(self):
+        """
+        Check Alignak-app files
+
+        :return: if all files are present
+        :rtype: bool
+        """
+
+        app_folders = [
+            'css', 'images'
+        ]
+        app_files = [
+            'images.ini', 'settings.cfg'
+        ]
+
+        if 'win32' not in sys.platform:
+            app_folders.append('bin')
+            app_folders.append('bin-samples')
+
+            app_files.append('bin-samples/%s-auto.sample.sh' % self.daemon_name)
+            app_files.append('bin-samples/%s.sample.sh' % self.daemon_name)
+
+        # Check App folders and files
+        for folder in app_folders:
+            try:
+                assert os.path.exists(os.path.join(os.environ['ALIGNAKAPP_APP_DIR'], folder))
+            except AssertionError:
+                print('The [%s] folder seems to be missing in "%s" !' %
+                      (folder, self.app_dir))
+                sys.exit(1)
+
+        for app_file in app_files:
+            try:
+                assert os.path.isfile(os.path.join(os.environ['ALIGNAKAPP_APP_DIR'], app_file))
+            except AssertionError:
+                print('The [%s] file seems to be missing in "%s" !' %
+                      (app_file, os.environ['ALIGNAKAPP_APP_DIR']))
+                sys.exit(1)
+
+        return True
+
+    def init_environment(self):
+        """
+        Assign environment variables to fields if they exists
+
+        """
+
+        if 'ALIGNAKAPP_APP_DIR' in os.environ:
+            self.app_dir = os.environ['ALIGNAKAPP_APP_DIR']
+
+        if 'ALIGNAKAPP_USR_DIR' in os.environ:
+            self.usr_cfg = os.environ['ALIGNAKAPP_USR_DIR']
+
+        if 'ALIGNAKAPP_LOG_DIR' in os.environ:
+            self.log_dir = os.environ['ALIGNAKAPP_LOG_DIR']
+
+    def check_environment(self, mode='start'):
+        """
+        Assign fields to environment variables if they don't exist
+
+        """
+
+        if 'ALIGNAKAPP_APP_DIR' not in os.environ:
+            os.environ['ALIGNAKAPP_APP_DIR'] = self.app_dir
+
+        if 'ALIGNAKAPP_USR_DIR' not in os.environ:
+            os.environ['ALIGNAKAPP_USR_DIR'] = self.usr_cfg
+
+        if 'ALIGNAKAPP_LOG_DIR' not in os.environ:
+            os.environ['ALIGNAKAPP_LOG_DIR'] = self.log_dir
+
+        for env_var in ['ALIGNAKAPP_APP_DIR', 'ALIGNAKAPP_USR_DIR', 'ALIGNAKAPP_LOG_DIR']:
+            try:
+                os.environ[env_var]
+            except KeyError as e:
+                print('Environment variable missing: %s' % e)
+                sys.exit(1)
+
+            if 'ALIGNAKAPP_APP_DIR' not in env_var:
+                try:
+                    assert os.access(os.environ[env_var], os.W_OK)
+                except AssertionError:
+                    print('[!] User don\'t have permission on %s !' % os.environ[env_var])
+                    sys.exit(1)
+
+        if 'install' in mode:
+            print('- Default %s Environment:' % __application__)
+            print('\t[ALIGNAKAPP_APP_DIR] = %s' % os.environ['ALIGNAKAPP_APP_DIR'])
+            print('\t[ALIGNAKAPP_USR_DIR] = %s' % os.environ['ALIGNAKAPP_USR_DIR'])
+            print('\t[ALIGNAKAPP_LOG_DIR] = %s' % os.environ['ALIGNAKAPP_LOG_DIR'])
+
+    def check_user_installation(self):
+        """
+        Check user installation files
+
+        """
+
+        usr_cfg_file = os.path.join(os.environ['ALIGNAKAPP_USR_DIR'], 'settings.cfg')
+        try:
+            assert os.path.isfile(usr_cfg_file)
+        except AssertionError as e:
+            print(e)
+            print('- [!] There is no [settings.cfg] file in [ALIGNAKAPP_USR_DIR] folder !')
+            print('\tPlease launch "%s.py --install before start."' % self.daemon_name)
+            sys.exit(1)
+
+    def install(self):
+        """
+        Install Alignak-app user files on system
+
+        """
+
+        install_file(
+            os.environ['ALIGNAKAPP_APP_DIR'],
+            os.environ['ALIGNAKAPP_USR_DIR'],
+            'settings.cfg'
+        )
+
+        if 'win32' not in sys.platform:
+            bin_folder = '%s/bin' % os.environ['HOME']
+            bin_file = '%s/bin/%s' % (os.environ['ALIGNAKAPP_APP_DIR'], self.daemon_name + '.py')
+            if not os.path.exists(bin_folder):
+                mkdir(bin_folder)
+
+            write_file(
+                os.path.join(os.environ['ALIGNAKAPP_APP_DIR'], 'bin-samples'),
+                bin_folder,
+                '%s.sample.sh' % self.daemon_name,
+                (
+                    self.daemon_name, os.path.join(os.environ['ALIGNAKAPP_APP_DIR'], bin_file),
+                    os.environ['ALIGNAKAPP_APP_DIR'], os.environ['ALIGNAKAPP_USR_DIR'],
+                    os.environ['ALIGNAKAPP_LOG_DIR'], __version__, __releasenotes__,
+                    __project_url__, __doc_url__,
+                )
+            )
+            file_executable(
+                os.path.join(bin_folder, self.daemon_name)
+            )
+            write_file(
+                os.path.join(os.environ['ALIGNAKAPP_APP_DIR'], 'bin-samples'),
+                bin_folder,
+                '%s-auto.sample.sh' % self.daemon_name,
+                (
+                    os.path.join(bin_folder, self.daemon_name),
+                    self.daemon_name
+                )
+            )
+            write_rc_file(os.path.join(bin_folder, '%s-auto' % self.daemon_name))
+
+        return True
diff --git a/alignak_app/utils/logs.py b/alignak_app/utils/logs.py
index b567a82..66aaccc 100644
--- a/alignak_app/utils/logs.py
+++ b/alignak_app/utils/logs.py
@@ -23,10 +23,6 @@
     Logs
     ++++
     Logs manage application log directory and file
-
-    The following environment variables are managed in this file:
-
-    * ``ALIGNAKAPP_LOG_DIR``: folder that contains log files of Alignak-app
 """
 
 import os
diff --git a/alignak_app/utils/system.py b/alignak_app/utils/system.py
new file mode 100644
index 0000000..da0a159
--- /dev/null
+++ b/alignak_app/utils/system.py
@@ -0,0 +1,205 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015-2018:
+#   Matthieu Estrada, ttamalfor@gmail.com
+#
+# This file is part of (AlignakApp).
+#
+# (AlignakApp) is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# (AlignakApp) is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with (AlignakApp).  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+    System
+    ++++++
+    System manage interactions with folders and files for Alignak-app
+"""
+
+import os
+import sys
+import stat
+
+import configparser
+from configparser import DuplicateOptionError, DuplicateSectionError
+
+from shutil import copyfile
+
+
+def mkdir(folder):
+    """
+    Make wanted folder
+
+    :param folder: folder to create
+    :type folder: str
+    :return: if creation is success or not
+    :rtype: bool
+    """
+
+    try:
+        os.makedirs(folder)
+        return True
+    except (PermissionError, FileExistsError) as e:
+        print('Can\'t create App directory for user in [%s] !\n%s' % (folder, e))
+        return False
+
+
+def install_file(origin_dir, dest_dir, filename):
+    """
+    Install (copy) filename from an origin folder to a destination folder
+
+    :param origin_dir: origin folder where file to copy is located
+    :type origin_dir: str
+    :param dest_dir: destination folder where file will be copied
+    :type dest_dir: str
+    :param filename: name of file to copy
+    :type filename: str
+    """
+
+    origin_file = os.path.join(origin_dir, filename)
+
+    dest_file = os.path.join(dest_dir, filename)
+    output_msg = ''
+
+    if not os.path.isfile(dest_file):
+        output_msg += '\t[%s] has been added.' % filename
+        try:
+            copyfile(origin_file, dest_file)
+        except IOError as e:
+            sys.exit(e)
+    else:
+        output_msg += '\t[%s] already exist.' % filename
+
+    output_msg += '\n\t  - Example file added in "%s"' % dest_dir
+    dest_file = dest_file + '.sample'
+    try:
+        copyfile(origin_file, dest_file)
+    except IOError as e:
+        sys.exit(e)
+
+    print(output_msg)
+
+
+def write_file(origin_dir, dest_dir, filename, formatted_var=None):
+    """
+    Write a file from an origiin to a destination, with formatted variables if needed
+
+    :param origin_dir: origin folder where file is located
+    :type origin_dir: str
+    :param dest_dir: destination folder where file will be located
+    :type dest_dir: str
+    :param filename: name of file to write
+    :type filename: str
+    :param formatted_var: tuple of variable to format origin file
+    :type formatted_var: tuple
+    """
+
+    origin_file = os.path.join(origin_dir, filename)
+    dest_file = os.path.join(dest_dir, filename.replace('.sample.sh', ''))
+
+    if os.path.isfile(dest_file):
+        print('\t[%s] file has been updated.' % os.path.split(dest_file)[1])
+    else:
+        print('\t[%s] file has been created.' % os.path.split(dest_file)[1])
+
+    orig_read_file = open(origin_file)
+    if formatted_var:
+        orig_format_file = orig_read_file.read() % formatted_var
+    else:
+        orig_format_file = orig_read_file.read()
+
+    with open(dest_file, 'w') as bin_file:
+        for line in orig_format_file:
+            bin_file.write(line)
+
+
+autocompletion_text = """
+# Alignak-app completion:
+if [ -f %s ]; then
+    . %s
+fi\n
+"""
+
+
+def write_rc_file(filename):
+    """
+    Write RC file to add autocompletion for Alignak-app
+
+    :param filename: name of file for autocompletion
+    :type filename: str
+    """
+
+    # Add auto completion
+    user_rc = ''
+    for autocomplete_file in ['.bashrc', '.zshrc']:
+        if os.path.isfile('%s/%s' % (os.environ['HOME'], autocomplete_file)):
+            user_rc = '%s/%s' % (os.environ['HOME'], autocomplete_file)
+
+            break
+
+    full_autocompletion_text = autocompletion_text % (filename, filename)
+
+    try:
+        bashrc = open(user_rc, 'r')
+        if full_autocompletion_text not in bashrc.read():
+            print('- Add autocompletion inside [%s]' % user_rc)
+            bashrc.close()
+            with open(user_rc, 'a') as cur_rc_file:
+                cur_rc_file.write(full_autocompletion_text)
+        else:
+            print('- Autocompletion already available.')
+            bashrc.close()
+    except IOError as e:
+        sys.exit(e)
+
+
+def read_config_file(cfg_parser, filename):
+    """
+    Read configuration file and assign it to configParser object
+
+    :param cfg_parser: configparser object
+    :type cfg_parser: configparser.ConfigParser
+    :param filename: name of file to read
+    :type filename: str
+    :return: corresponding filename if read is success
+    :rtype: str
+    """
+
+    try:
+        cfg_file = cfg_parser.read(filename)
+        if cfg_file:
+            return cfg_file[0]
+    except (DuplicateOptionError, DuplicateSectionError) as d:  # pragma: no cover
+        print('Duplicate Option/Section in file [%s] !' % filename)
+        sys.exit(d)
+    except Exception as ex:  # pragma: no cover - not testable
+        print('Configuration file [%s] is missing !' % filename)
+        sys.exit(ex)
+
+    return None
+
+
+def file_executable(filename):
+    """
+    Make filename executable
+
+    :param filename: file to make executable
+    :type filename: str
+    """
+
+    try:
+        st = os.stat(filename)
+        os.chmod(filename, st.st_mode | stat.S_IEXEC)
+    except PermissionError as e:
+        print(e)
+        print('Can\'t make file executable: %s' % filename)
+        sys.exit(1)
diff --git a/bin/unix/alignak-app-auto.sample.sh b/bin/unix/alignak-app-auto.sample.sh
index 6abe41a..a9588f1 100644
--- a/bin/unix/alignak-app-auto.sample.sh
+++ b/bin/unix/alignak-app-auto.sample.sh
@@ -19,6 +19,12 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with (AlignakApp).  If not, see <http://www.gnu.org/licenses/>.
 
+#############################################################################
+#                                                                           #
+#                     ALIGNAK-APP AUTOCOMPLETION                            #
+#                                                                           #
+#############################################################################
+
 _script()
 {
     _script_commands=$(%s shortlist)
diff --git a/bin/unix/alignak-app.py b/bin/unix/alignak-app.py
index d98d324..db73569 100755
--- a/bin/unix/alignak-app.py
+++ b/bin/unix/alignak-app.py
@@ -20,7 +20,9 @@
 # along with (AlignakApp).  If not, see <http://www.gnu.org/licenses/>.
 
 """
-    Launch Alignak-app
+    Alignak App
+    +++++++++++
+    Alignak App launch or install Alignak-app
 """
 
 import sys
@@ -28,15 +30,14 @@
 
 import argparse
 
-from alignak_app.utils.install import install_alignak_app
-from alignak_app.utils.config import settings
-from alignak_app.app import AlignakApp
+from alignak_app.utils.installer import Installer
+
 from alignak_app import __application__
 
 
 def main():  # pragma: no cover
     """
-    Define arguments and send to DataConverter()
+        Launch or install Alignak-app
     """
 
     usage = u"./alignak-app.py [--start | --install]"
@@ -51,38 +52,40 @@ def main():  # pragma: no cover
         description=description
     )
 
+    parser.add_argument(
+        '-i', '--install',
+        help='Check installation and install folders for each user. '
+             'If you installed %s as sudo, run this command first.' % __application__,
+        dest='install', action="store_true", default=False
+    )
+
     parser.add_argument(
         '-s', '--start',
         help='Start %s in your shell.' % __application__,
         dest='start', action="store_true", default=False
     )
 
-    if 'win32' not in sys.platform:
-        parser.add_argument(
-            '-i', '--install',
-            help='Install or update %s daemon, with your environment variables.' % __application__,
-            dest='install', action="store_true", default=False
-        )
-
     args = parser.parse_args()
+    installer = Installer()
 
     if args.start:
-        if 'SSH_CONNECTION' in os.environ:
-            fail = '\033[91m'
-            endc = '\033[0m'
+        # Check installation
+        installer.check_installation()
+
+        from alignak_app.app import AlignakApp
 
+        if 'SSH_CONNECTION' in os.environ:
             sys.exit(
-                '%sAlignak-app can not be launched during an SSH connection '
-                'and requires an X server to be displayed.%s' % (fail, endc)
+                'Alignak-app can not be launched during an SSH connection '
+                'and requires an X server to be displayed.'
             )
 
         alignak_app = AlignakApp()
         alignak_app.start()
-
-    elif args.install and 'win32' not in sys.platform:
-        # ONLY FOR LINUX PLATFORM
-        bin_file = '%s/bin/%s' % (settings.app_cfg_dir, os.path.split(__file__)[1])
-        install_alignak_app(bin_file)
+    elif args.install:
+        # Check installation and install
+        installer.check_installation(mode='install')
+        installer.install()
     else:
         parser.print_help()
 
diff --git a/bin/unix/alignak-app.sample.sh b/bin/unix/alignak-app.sample.sh
index 39bbdec..c1150e7 100755
--- a/bin/unix/alignak-app.sample.sh
+++ b/bin/unix/alignak-app.sample.sh
@@ -29,13 +29,19 @@
 # Description:       alignak-app is a desktop application for Alignak solution.
 ### END INIT INFO
 
+#############################################################################
+#                                                                           #
+#                           DAEMON ALIGNAK-APP                              #
+#                                                                           #
+#############################################################################
+
 # Variables
 DAEMON=%s
 BIN_FILE=%s
 PYBIN=python3
 
-export ALIGNAKAPP_APP_CFG=%s
-export ALIGNAKAPP_USER_CFG=%s
+export ALIGNAKAPP_APP_DIR=%s
+export ALIGNAKAPP_USR_DIR=%s
 export ALIGNAKAPP_LOG_DIR=%s
 
 APP_VERSION="%s"
@@ -47,14 +53,14 @@ APP_DOC_URL="%s"
 usage() {
     echo "------------------------------------------"
     echo "Alignak-app, Version $APP_VERSION \n"
-    echo "  $APP_RELEASE_NOTES"
-    echo "  For more help, visit $APP_DOC_URL."
-    echo "  Please open any issue on $APP_PROJECT_URL."
+    echo "\t$APP_RELEASE_NOTES"
+    echo "\tFor more help, visit $APP_DOC_URL."
+    echo "\tPlease open any issue on $APP_PROJECT_URL."
     echo "------------------------------------------"
-    echo "Alignak-app will use following variables: \n"
-    echo "ALIGNAKAPP_APP_CFG = $ALIGNAKAPP_APP_CFG"
-    echo "ALIGNAKAPP_USER_CFG = $ALIGNAKAPP_USER_CFG"
-    echo "ALIGNAKAPP_LOG_DIR = $ALIGNAKAPP_LOG_DIR"
+    echo "Alignak-App Environment: \n"
+    echo "\tALIGNAKAPP_APP_DIR = $ALIGNAKAPP_APP_DIR"
+    echo "\tALIGNAKAPP_USR_DIR = $ALIGNAKAPP_USR_DIR"
+    echo "\tALIGNAKAPP_LOG_DIR = $ALIGNAKAPP_LOG_DIR"
     echo "\n Usage: $DAEMON {start|stop|status|restart} \n"
 }
 
diff --git a/bin/win/alignak-app-win-setup.iss b/bin/win/alignak-app-win-setup.iss
index 540a36c..838a13f 100644
--- a/bin/win/alignak-app-win-setup.iss
+++ b/bin/win/alignak-app-win-setup.iss
@@ -74,8 +74,9 @@ Source: "{#RootApp}\alignak-app\bin\win\icon_64.ico"; DestDir: {app}; Flags: ign
 Source: "{#RootApp}\alignak-app\alignak_app\locales\LC_MESSAGES\*"; DestDir: {app}\locales; Flags: ignoreversion; Permissions: users-full admins-full everyone-modify;
 
 [Registry]
-Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName: "ALIGNAKAPP_USER_CFG"; ValueData: "{app}"; Flags: uninsdeletekey preservestringtype
-Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName: "ALIGNAKAPP_APP_CFG"; ValueData: "{app}"; Flags: uninsdeletekey preservestringtype
+Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName: "ALIGNAKAPP_USR_DIR"; ValueData: "{app}"; Flags: uninsdeletekey preservestringtype
+Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName: "ALIGNAKAPP_APP_DIR"; ValueData: "{app}"; Flags: uninsdeletekey preservestringtype
+Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName: "ALIGNAKAPP_LOG_DIR"; ValueData: "{app}"; Flags: uninsdeletekey preservestringtype
 
 [Icons]
 Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\icon_64.ico";
diff --git a/docs/api.rst b/docs/api.rst
index 6fe4201..dd23906 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -1,14 +1,17 @@
 .. _api:
 
-Alignak-app API
-===============
+Alignak-app Architecture
+========================
 
 .. automodule:: alignak_app
     :members:
     :show-inheritance:
 
 Alignak-App
-~~~~~~~~~~~
+===========
+
+Main Class
+~~~~~~~~~~
 
 .. automodule:: alignak_app.app
     :members:
@@ -95,7 +98,12 @@ Utils
     :show-inheritance:
 
 
-.. automodule:: alignak_app.utils.install
+.. automodule:: alignak_app.utils.installer
+    :members:
+    :inherited-members:
+    :show-inheritance:
+
+.. automodule:: alignak_app.utils.system
     :members:
     :inherited-members:
     :show-inheritance:
diff --git a/docs/conf.py b/docs/conf.py
index 101bc3a..82b7b0b 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -22,6 +22,10 @@
 from alignak_app import __version__, __short_version__
 from alignak_app import __copyright__, __author__, __application__
 
+os.environ['ALIGNAKAPP_USR_DIR'] = os.path.abspath('../etc')
+os.environ['ALIGNAKAPP_APP_DIR'] = os.path.abspath('../etc')
+os.environ['ALIGNAKAPP_LOG_DIR'] = os.path.abspath('../etc')
+
 # -- General configuration ------------------------------------------------
 
 # If your documentation needs a minimal Sphinx version, state it here.
diff --git a/docs/config.rst b/docs/config.rst
index d67adc4..0399f27 100644
--- a/docs/config.rst
+++ b/docs/config.rst
@@ -1,15 +1,15 @@
 .. _config:
 
-Alignak-app Env Variables
-=========================
+Environment Variables
+=====================
 
 During installation, Alignak-app creates some folders that contains all the files application need to run.
 Then she will keep them in **environment variables**.
 
 The application will normally automatically detect the folders used by the application and use environment variables for this purpose.
 
-  * ``ALIGNAKAPP_USR_CFG``: this folder is used by application for read the ``settings.cfg`` file . By default, Alignak-app will log also in this directory.
-  * ``ALIGNAKAPP_APP_CFG``: this folder is used by application for read ``images.ini`` file, ``style.css`` and get images. This variable is normally equal to the ROOT folder described above. **Be careful if you define this variable yourself!**
+  * ``ALIGNAKAPP_USR_DIR``: this folder is used by application for read the ``settings.cfg`` file . By default, Alignak-app will log also in this directory.
+  * ``ALIGNAKAPP_APP_DIR``: this folder is used by application for read ``images.ini`` file, ``style.css`` and get images. This variable is normally equal to the ROOT folder described above. **Be careful if you define this variable yourself!**
   * ``ALIGNAKAPP_LOG_DIR``: this folder is used to create the log file of Alignak-app.
 
 During Windows installation, if you used **Installer**, these variables are automatically filled.
@@ -17,11 +17,11 @@ During Windows installation, if you used **Installer**, these variables are auto
 On Linux
 --------
 
-Alignak-app will try to create ``ALIGNAKAPP_USR_CFG`` for later configurations. By default this folder should be::
+Alignak-app will try to create ``ALIGNAKAPP_USR_DIR`` for later configurations. By default this folder should be::
 
     /$HOME/.local/alignak_app/
 
-The ``ALIGNAKAPP_APP_CFG`` should be under one of the following folders and is create by pip during installation::
+The ``ALIGNAKAPP_APP_DIR`` should be under one of the following folders and is create by pip during installation::
 
     /$HOME/.local/alignak_app/
     /usr/local/alignak_app/
@@ -29,13 +29,13 @@ The ``ALIGNAKAPP_APP_CFG`` should be under one of the following folders and is c
 On Windows
 ----------
 
-On Windows, use **Installer** is recommended (see :ref:`install`) to respect Windows conventions.
-``ALIGNAKAPP_USR_CFG`` and ``ALIGNAKAPP_APP_CFG`` variables are by default set to::
+On Windows, use **Installer** is recommended (see :ref:`installer`) to respect Windows conventions.
+``ALIGNAKAPP_USR_DIR`` and ``ALIGNAKAPP_APP_DIR`` variables are by default set to::
 
     C:\Program Files\Alignak-app\
 
 If you install by ``pip`` under Windows, you may need to **define these variables yourself** !
-And ``ALIGNAKAPP_USR_CFG`` and ``ALIGNAKAPP_APP_CFG`` variables should be by default set to::
+And ``ALIGNAKAPP_USR_DIR`` and ``ALIGNAKAPP_APP_DIR`` variables should be by default set to::
 
     C:\Users\user\AppData\Roaming\Python\alignak_app\
 
@@ -44,7 +44,7 @@ Configuration
 
 Before running application, **you must configure it**.
 
-You will find a ``settings.cfg`` file located in the ``ALIGNAKAPP_USR_CFG`` folder cited above.
+You will find a ``settings.cfg`` file located in the ``ALIGNAKAPP_USR_DIR`` folder cited above.
 
 This file contains Sections who are introduced by a ``[section_name]`` header. Then, it contains ``name = value`` entries.
 All parameters are also explained in file. For the boolean parameters, you can use the following values: on/off, true/false or 1/0.
diff --git a/docs/index.rst b/docs/index.rst
index fff7d18..eeb2f6e 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -12,7 +12,7 @@ Documentation content:
     :maxdepth: 3
 
     intro
-    install
+    installer
     config
     launch
     use
@@ -26,4 +26,3 @@ Indices and tables
 * :ref:`genindex`
 * :ref:`modindex`
 * :ref:`search`
-
diff --git a/docs/install.rst b/docs/installer.rst
similarity index 66%
rename from docs/install.rst
rename to docs/installer.rst
index 5e0d81d..6dfe449 100644
--- a/docs/install.rst
+++ b/docs/installer.rst
@@ -1,7 +1,7 @@
-.. _install:
+.. _installer:
 
-Install Alignak-app
-===================
+Alignak-app Installers
+======================
 
 Requirements
 ------------
@@ -16,8 +16,13 @@ You must have Alignak Suite installed before using this app :
 
 Alignak-app need at least a functionnal and available **alignak-backend** to connect with it !
 
-Windows Users
--------------
+Python 3
+~~~~~~~~
+
+You must have **Python 3** installed on your system. Only the Windows installer does not need to install Python 3.
+
+Installation (Windows)
+----------------------
 
 An installer is available in repository of Alignak-app on `releases page <https://github.com/Alignak-monitoring-contrib/alignak-app/releases>`_.
 It is **recommended** that you use this installer to run Alignak-app on Windows.
@@ -28,31 +33,26 @@ It is **recommended** that you use this installer to run Alignak-app on Windows.
 
 **IMPORTANT:** This installer is currently only compatible with **x64** architecture !
 
-Linux Users
------------
+You can also buid your own Windows installer (on **develop** branch for example), see :ref:`setup` for more information.
 
-You can install with pip::
+However, you can install the application in the same way as under Linux, but this will require you to keep a window open for Python.
 
-    pip3 install alignak_app
+Installation (Linux)
+--------------------
 
-The required Python modules are automatically installed if not present on your system.
+You can install Alignak-app like other python libraries, with ``pip3``::
 
-If you install App as a root user (with ``sudo``), App wil automatically create a folder for user if you launch App with another user.
-
-From Sources
-------------
+    pip3 install alignak_app
 
-External Libraries
-~~~~~~~~~~~~~~~~~~
+The required Python modules are automatically installed, if not present on your system.
 
-You need to install Python modules that are listed in ``requirements.txt`` file with pip:
+If you install App as a root user (with ``sudo``), you have to run ``--install`` command before launch Alignak-App ! (see :ref:`launch`)
 
-    .. literalinclude:: ../requirements.txt
+Installation (From Sources)
+---------------------------
 
-**Note**: if you proceed to an end-user installation with pip, the required modules are automatically installed.
-
-Installation
-~~~~~~~~~~~~
+Clone and install
+~~~~~~~~~~~~~~~~~
 
 To install from source, clone repos and install with pip ::
 
@@ -61,6 +61,13 @@ To install from source, clone repos and install with pip ::
     # If you're under Windows, use "pip" instead "pip3"
     pip3 install .
 
+External Libraries
+~~~~~~~~~~~~~~~~~~
+
+You need to install Python modules that are listed in ``requirements.txt`` file with pip:
+
+    .. literalinclude:: ../requirements.txt
+
 Under Windows
 ~~~~~~~~~~~~~
 
@@ -74,6 +81,5 @@ Replace ``<USERNAME>`` by your username.
 
 Be sure also that you've install Python3 on your device.
 
-
 .. _alignak: http://alignak-monitoring.github.io/
 .. _alignak-backend: http://alignak-backend.readthedocs.io/en/latest/
diff --git a/docs/launch.rst b/docs/launch.rst
index 039ad60..c06fe48 100644
--- a/docs/launch.rst
+++ b/docs/launch.rst
@@ -20,12 +20,12 @@ To launch application use ``--start``::
 
     /usr/local/alignak_app/bin/alignak-app.py --start
 
+If you have set environment variables for application, they will be added to the generated daemon script (see :ref:`config`).
+
 To generate an Alignak-app daemon file, use ``--install``::
 
     /usr/local/alignak_app/bin/alignak-app.py --install
 
-If you have set environment variables for application, they will be added to the generated script (see :ref:`config`).
-
 Launch daemon
 *************
 
@@ -39,7 +39,7 @@ Here is the available commands::
 
 With no parameters, this will display help and your environment variables configuration.
 
-**Note:** To generate a new daemon file with other environment variable, just run ``alignak-app.py --install`` again.
+**Note:** To generate a new daemon file with other environment, just run ``alignak-app.py --start`` again with your new environment variables.
 
 On Windows
 ~~~~~~~~~~
@@ -65,8 +65,11 @@ Solve Problems
 
 If you're having trouble getting started and running the app, here are some things to check:
 
-1. Be sure you have correctly set your configuration file (see above) and that you can join your backend.
-2. The application generates a log file in its root folder (see :ref:`config`). Search for ``ERROR`` messages.
-3. If you have installed Alignak-app with pip, be sure to add the flag *--user* (see :ref:`install`).
+1. Be sure you have correctly:
 
+  * Install application: see :ref:`installer`.
+  * Set your configuration file: see :ref:`config`.
 
+2. The application generates a log file in folder defined in ``ALIGNAKAPP_LOG_DIR`` (see :ref:`config`). Search for ``ERROR`` messages in this file.
+3. For more help you can set ``debug`` to **yes** to have more informations.
+4. That your backend is reachable from your computer.
diff --git a/docs/use.rst b/docs/use.rst
index 80a3d72..692830a 100644
--- a/docs/use.rst
+++ b/docs/use.rst
@@ -3,11 +3,34 @@
 Alignak-app Interface
 =====================
 
-System Tray
------------
+Login Window
+------------
 
-Once Alignak-app is started, you'll have an icon in your task bar (in bottow right under Windows, top right under Ubuntu for example).
-When you click on this icon, you'll have access to multiple menu like "dock", "about" or configurations.
+If you have not set your configuration file, Alignak-app will display a login window by default.
+In this window, you'll be able to:
+
+* Configure your Alignak server (by clicking on **server** icon).
+* Type your **username** and **password** to login.
+
+Start
+-----
+
+Once you're connected, Alignak-app will start and show you a progress bar. Time to start will depend on your installation (a backend with a lot of host and services will take more time).
+
+When Alignak-app has started, you'll have:
+
+* The **Main Window** of App, separated into two parts:
+
+  * The "App Dock" (Right part)
+  * The "App Panel" (Left part)
+
+* A **Tray Icon** in your task bar. This icon gives you access to a menu with:
+
+  * Alignak-app menu, to view the app if it has been reduced
+  * About menu, to show informations of Alignak-app
+  * Reload menu, to reload your configuration.
+
+Other menu will come in future versions.
 
 App Dock (Right part)
 ---------------------
@@ -59,18 +82,43 @@ App Panel (Left part)
 
 The left part of application (called "Panel"), will display a **Hosts Synthesis View**. This is where you can see your monitored hosts and services.
 
-At the top of this window, you will find a summary of the number of items for each state (OK, CRITICAL, DOWN...).
+Host Synthesis
+~~~~~~~~~~~~~~
+
+**Dashboard:**
+
+At the top of this window, you will find a dashboard with the number of items, for each state (OK, CRITICAL, DOWN...).
+
+**Host View:**
 
 Start typing the name of a host in the search bar and App will propose to you different corresponding names.
 When you select a host, its information and the list of its services will be displayed.
 
+*Services:*
+
+When a host is displayed, you will have the list of services, classified by aggregation. Click on one of them to display them.
+
+If you click on a service, a summary of its status will be displayed on the right.
+
+**Actions:**
 You will then be able to perform various actions such as seeing the details of each of its services, acknowledging a problem or planning a downtime for an item (service or host).
 
-You will also have access to the host's history. It may take a while to be available. It depends on the number of hosts monitored in backend.
+You will also have access to the host's history. It may take a while to be available.
 
 Another tab called "Problems" is used to display the problems listed by the backend (like a DOWN host or a CRITICAL service).
 
-WebUI
------
+Problems
+~~~~~~~~
+
+Other tab will display problems found by Alignak-app in backend.
+
+This will bring together down hosts, critical services or any other worries, such as an unreachable host.
+
+You'll be able to acknowledge problems or trigger downtimes.
+
+WebUI Integration
+-----------------
+
+App also have lot of buttons which bring you to WebUI. You've to set WebUI url in configuration file to make this buttons available.
 
-App also have lot of buttons which bring you to WebUI. You've to set WebUI url in configuration file to make this buttons available.
\ No newline at end of file
+App will be aware also on events trigger in WebUI in host history.
\ No newline at end of file


Test patch:
diff --git a/test/setup_test.sh b/test/setup_test.sh
index a9cfa5a..83c2758 100755
--- a/test/setup_test.sh
+++ b/test/setup_test.sh
@@ -40,6 +40,11 @@ pip install --upgrade -r test/requirements.txt
 echo '--------- Check and copy folder data to home... --------- '
 mkdir -p ~/.local/alignak_app/images/
 mkdir -p ~/.local/alignak_app/css/
+mkdir -p ~/.local/alignak_app/bin/
+mkdir -p ~/.local/alignak_app/bin-samples/
 cp -R --verbose etc/images/* ~/.local/alignak_app/images/
 cp -R --verbose etc/css/* ~/.local/alignak_app/css/
 cp -R --verbose test/etc/* ~/.local/alignak_app/
+cp --verbose bin/unix/alignak-app.py ~/.local/alignak_app/bin/
+cp --verbose bin/unix/alignak-app.sample.sh ~/.local/alignak_app/bin-samples/
+cp --verbose bin/unix/alignak-app-auto.sample.sh ~/.local/alignak_app/bin-samples/
diff --git a/test/test_about_dialog.py b/test/test_about_dialog.py
index ccdb5ff..b145310 100644
--- a/test/test_about_dialog.py
+++ b/test/test_about_dialog.py
@@ -24,10 +24,13 @@
 import unittest2
 from PyQt5.QtWidgets import QApplication, QLabel
 
+from alignak_app.utils.installer import Installer
 from alignak_app.utils.config import settings
 from alignak_app.locales.locales import init_localization
 from alignak_app.qobjects.systray.about import AboutQDialog
 
+installer = Installer()
+installer.check_installation()
 settings.init_config()
 init_localization()
 
diff --git a/test/test_config.py b/test/test_config.py
index 2b8f53b..ab40962 100644
--- a/test/test_config.py
+++ b/test/test_config.py
@@ -23,6 +23,7 @@
 import unittest2
 import configparser
 
+from alignak_app.utils.installer import Installer
 from alignak_app.utils.config import get_url_endpoint_from_icon_name, Settings
 
 
@@ -31,6 +32,9 @@ class TestUtils(unittest2.TestCase):
         This file test methods of `utils.py` file.
     """
 
+    installer = Installer()
+    installer.check_installation()
+
     def test_init_config(self):
         """Init Settings"""
 
@@ -40,9 +44,7 @@ def test_init_config(self):
         self.assertIsInstance(under_test.img_config, configparser.ConfigParser)
         self.assertTrue('settings' in under_test.settings)
         self.assertTrue('images' in under_test.settings)
-        self.assertIsNone(under_test.app_cfg_dir)
-        self.assertIsNone(under_test.user_cfg_dir)
-        self.assertIsNone(under_test.css_style)
+        self.assertFalse(under_test.css_style)
 
         under_test.init_config()
 
@@ -50,29 +52,7 @@ def test_init_config(self):
         self.assertIsInstance(under_test.img_config, configparser.ConfigParser)
         self.assertTrue('settings' in under_test.settings)
         self.assertTrue('images' in under_test.settings)
-        self.assertIsNotNone(under_test.app_cfg_dir)
-        self.assertIsNotNone(under_test.user_cfg_dir)
-        self.assertIsNone(under_test.css_style)
-
-    def test_app_dir_from_env(self):
-        """App Workdir from Env"""
-
-        under_test = Settings()
-        under_test.init_config()
-
-        self.assertEqual('%s/.local/alignak_app' % os.environ['HOME'], under_test.user_cfg_dir)
-
-        os.environ['ALIGNAKAPP_USR_CFG'] = '/tmp/alignak_app'
-        os.environ['ALIGNAKAPP_APP_CFG'] = '/tmp/alignak_app/settings'
-
-        under_test.init_config()
-
-        self.assertEqual('/tmp/alignak_app', under_test.user_cfg_dir)
-        self.assertEqual('/tmp/alignak_app/settings', under_test.app_cfg_dir)
-
-        # Reset env var for other tests
-        os.environ['ALIGNAKAPP_USR_CFG'] = ''
-        os.environ['ALIGNAKAPP_APP_CFG'] = ''
+        self.assertFalse(under_test.css_style)
 
     def test_set_app_config(self):
         """Set and Get app_config"""
@@ -107,12 +87,12 @@ def test_get_image(self):
 
         test_icon = under_test.get_image('icon')
 
-        self.assertEqual('%s/images/icon.svg' % under_test.app_cfg_dir, test_icon)
+        self.assertEqual('%s/images/icon.svg' % os.environ['ALIGNAKAPP_APP_DIR'], test_icon)
 
         test_icon_error = under_test.get_image('NONE')
 
         self.assertEqual(
-            '%s/images/error.svg' % under_test.app_cfg_dir, test_icon_error
+            '%s/images/error.svg' % os.environ['ALIGNAKAPP_APP_DIR'], test_icon_error
         )
 
     def test_init_css(self):
@@ -121,15 +101,15 @@ def test_init_css(self):
         under_test = Settings()
         under_test.init_config()
 
-        self.assertIsNone(under_test.css_style)
+        self.assertFalse(under_test.css_style)
 
         under_test.init_css()
 
-        self.assertIsNotNone(under_test.css_style)
+        self.assertTrue(under_test.css_style)
         self.assertIsInstance(under_test.css_style, str)
 
-        # Set 'ALIGNAKAPP_APP_CFG' and init again config
-        os.environ['ALIGNAKAPP_APP_CFG'] = '/tmp/alignak_app'
+        # Set 'ALIGNAKAPP_APP_DIR' and init again config
+        os.environ['ALIGNAKAPP_APP_DIR'] = '/tmp/alignak_app'
         under_test.init_config()
 
         under_test.init_css()
@@ -137,7 +117,7 @@ def test_init_css(self):
         self.assertEqual('', under_test.css_style)
 
         # Reset env var for other tests
-        os.environ['ALIGNAKAPP_APP_CFG'] = ''
+        os.environ['ALIGNAKAPP_APP_DIR'] = ''
 
     def test_get_url_endpoint_from_icon_name(self):
         """Get Url Endpoint from Icon Name"""