#!/usr/bin/env python
# Copyright 2013 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import crypt
from fuelmenu.common import modulehelper as helper
from fuelmenu.common import utils

import logging
import urwid

log = logging.getLogger('fuelmenu.rootpw')
blank = urwid.Divider()


class RootPassword(urwid.WidgetWrap):
    def __init__(self, parent):
        self.name = "Root Password"
        self.visible = True
        self.parent = parent
        # UI text
        self.header_content = ["Set root user password", ""]
        self.fields = ["PASSWORD", "CONFIRM_PASSWORD"]
        self.defaults = \
            {
                "PASSWORD": {"label": "Enter password",
                             "tooltip": "Use ASCII characters only",
                             "value": ""},
                "CONFIRM_PASSWORD": {"label": "Confirm password",
                                     "tooltip": "Use ASCII characters only",
                                     "value": ""},
            }

        self.screen = None

    def check(self, args):
        """Validate that all fields have valid values and sanity checks."""
        self.parent.footer.set_text("Checking data...")
        self.parent.refreshScreen()
        # Get field information
        responses = dict()

        for index, fieldname in enumerate(self.fields):
            if fieldname != "blank":
                responses[fieldname] = self.edits[index].get_edit_text()

        # Validate each field
        errors = []

        password = responses["PASSWORD"]

        # Passwords must match
        if password != responses["CONFIRM_PASSWORD"]:
            errors.append("Passwords do not match.")

        # password needs to be in ASCII character set
        try:
            if password.decode('ascii'):
                pass
        except UnicodeDecodeError:
            errors.append("Password contains non-ASCII characters.")

        if len(errors) > 0:
            self.parent.footer.set_text("Errors occurred.")
            log.error("Errors: %s %s" % (len(errors), errors))
            helper.ModuleHelper.display_failed_check_dialog(self, errors)
            return False

        # check empty password
        if len(password) == 0:
            self.parent.footer.set_text("Password is empty, "
                                        "no changes will be made.")
            log.warning("Empty password, skipping.")
        else:
            self.parent.footer.set_text("No errors found.")
        return password

    def apply(self, args):
        password = self.check(args)
        if password is False:
            log.error("Check failed. Not applying")
            return False

        if len(password) > 0:
            return self.save(password)
        return True

    def save(self, password):
        if self.parent.save_only:
            # We shouldn't change root password in save_only mode
            return True

        hashed = crypt.crypt(password, utils.gensalt())
        log.info("Changing root password")
        # clear any locks first
        rm_command = ["rm", "-f", "/etc/passwd.lock", "/etc/shadow.lock"]
        utils.execute(rm_command)
        usermod_command = ["usermod", "-p", hashed, "root"]
        usermod_code, _, errout = utils.execute(usermod_command)

        if usermod_code == 0:
            self.parent.footer.set_text("Changes applied successfully.")
            log.info("Root password successfully changed.")
            # Reset fields
            self.cancel(None)
        else:
            log.error("Root password change failed with error:"
                      "\"{0}\"".format(errout))
            self.parent.footer.set_text("Unable to apply changes. Check logs "
                                        "for more details.")
            return False

        self.save_settings(hashed)
        return True

    def save_settings(self, hashed_pwd):
        newsettings = {'BOOTSTRAP': {
            'hashed_root_password': hashed_pwd,
        }}
        self.parent.settings.merge(newsettings)

    def cancel(self, button):
        helper.ModuleHelper.cancel(self, button)

    def refresh(self):
        pass

    def screenUI(self):
        return helper.ModuleHelper.screenUI(self, self.header_content,
                                            self.fields, self.defaults)
