"""
 *
 * This file is part of rasdaman community.
 *
 * Rasdaman community is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Rasdaman community 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  General Public License for more details.
 *
 * You should have received a copy of the GNU  General Public License
 * along with rasdaman community.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2003 - 2016 Peter Baumann / rasdaman GmbH.
 *
 * For more information please see <http://www.rasdaman.org>
 * or contact Peter Baumann via <baumann@rasdaman.com>.
 *
"""
from util.log import log
from util.timer import Timer
from services import linux_distro
from timeit import default_timer as timer


class Strategy:

    def __init__(self, validator, uninstaller, dep_installer, retriever, builder,
                 preparer, finalizer, tester, packager, install, uninstall):
        """
        The strategy associates all the components into one runnable object
        :param Validator validator: the validator for this installation
        :param Uninstaller uninstaller: existing rasdaman uninstaller
        :param OSInstaller dep_installer: the installer for the current os
        :param Retriever retriever: the retriever to be used in this strategy
        :param Builder builder: the builder to be used
        :param Preparer preparer: the preparer to be used
        :param Finalizer finalizer: the finalizer to be used
        :param Tester tester: the tester to be used
        :param Packager packager: the packager to be used
        :param bool install: if rasdaman should be installed
        :param bool uninstall: if rasdaman should be uninstalled
        """
        self.validator = validator
        self.uninstaller = uninstaller
        self.dep_installer = dep_installer
        self.retriever = retriever
        self.builder = builder
        self.preparer = preparer
        self.finalizer = finalizer
        self.tester = tester
        self.packager = packager
        self.install = install
        self.uninstall = uninstall
        self.timing_enabled = tester.is_enabled()

        self.STEPS = [
            ("Installing third party dependencies on {} {}...".format(
                linux_distro.get_distro_name(), str(linux_distro.get_distro_version())),
            self.install_deps, "Third party dependencies installed."),
            ("Retrieving rasdaman...", self.retrieve, "Rasdaman retrieved."),
            ("Building rasdaman...", self.build, "Rasdaman built."),
            ("Preparing rasdaman...", self.prepare, "Rasdaman prepared."),
            ("Finalizing installation...", self.finalize, "Installation finalized."),
            ("Testing rasdaman...", self.test, "Testing done."),
            ("Packaging...", self.package, "Packaging done.")
        ]

    def run(self):
        """
        Runs the strategy by:
         - retrieving rasdaman
         - building rasdaman
         - preparing the external dependencies
         - testing
         - finalize
         according to the installation profile
         :rtype: tester.tester.TestResult
        """
        total_start = timer()

        log.title("Validating system...")
        self.validate()
        log.title("System was validated.")

        if self.uninstall:
            log.title("Uninstalling existing rasdaman...")
            self.uninstaller.clean()
            log.title("Rasdaman uninstalled successfully.")

        if self.install:
            for (msg_before, execute, msg_after) in self.STEPS:
                start = timer()
                log.title(msg_before)
                execute()
                log.title(msg_after + self._get_step_elapsed(start))

            log.success("Rasdaman installation finished in " + self._get_elapsed(total_start))
            return self.test_result
        else:
            log.title("Rasdaman installation not requested, done.")
            return None

    def _get_step_elapsed(self, start):
        if self.timing_enabled:
            return " (" + self._get_elapsed(start) + ")"
        else:
            return ""

    def _get_elapsed(self, start):
        elapsed = (timer() - start) / 60.0
        elapsed_str = "%.1f" % elapsed # one decimal place
        return elapsed_str + "m"

    def validate(self):
        self.validator.validate()

    def install_deps(self):
        self.dep_installer.install()

    def retrieve(self):
        self.retriever.retrieve()

    def build(self):
        self.builder.build()

    def prepare(self):
        self.preparer.prepare()

    def finalize(self):
        self.finalizer.finalize()

    def test(self):
        self.test_result = self.tester.test()
        log.info(str(self.test_result))

    def package(self):
        self.packager.package()
