import os
import re
from cdist.core.pytypes import *
import argparse


class FileType(PythonType):
    def get_attribute(self, stat_file, attribute, value_should):
        if os.path.exists(stat_file):
            if re.match('[0-9]', value_should):
                index = 1
            else:
                index = 2
            with open(stat_file, 'r') as f:
                for line in f:
                    if re.match(attribute + ":", line):
                        fields = line.split()
                        return fields[index]
            return None

    def set_attribute(self, attribute, value_should, destination):
        cmd = {
            'group': 'chgrp',
            'owner': 'chown',
            'mode': 'chmod',
        }
        self.send_message("{} '{}'".format(cmd[attribute], value_should))
        return "{} '{}' '{}'".format(cmd[attribute], value_should, destination)

    def type_manifest(self):
        yield from ()

    def type_gencode(self):
        typeis = self.get_explorer('type')
        state_should = self.get_parameter('state')

        if state_should == 'exists' and typeis == 'file':
            return

        source = self.get_parameter('source')
        if source == '-':
            source = self.stdin_path
        destination = '/' + self.object_id
        if state_should == 'pre-exists':
            if source is not None:
                self.die('--source cannot be used with --state pre-exists')
            if typeis == 'file':
                return None
            else:
                self.die('File {} does not exist'.format(destination))

        create_file = False
        upload_file = False
        set_attributes = False
        fire_onchange = False
        code = []
        if state_should == 'present' or state_should == 'exists':
            if source is None:
                remote_stat = self.get_explorer('stat')
                if not remote_stat:
                    create_file = True
            else:
                if os.path.exists(source):
                    if typeis == 'file':
                        local_cksum = self.run_local(['cksum', source, ])
                        local_cksum = local_cksum.split()[0]
                        remote_cksum = self.get_explorer('cksum')
                        remote_cksum = remote_cksum.split()[0]
                        upload_file = local_cksum != remote_cksum
                    else:
                        upload_file = True
                else:
                    self.die('Source {} does not exist'.format(source))
            if create_file or upload_file:
                set_attributes = True
                fire_onchange = True
                tempfile_template = '{}.cdist.XXXXXXXXXX'.format(destination)
                destination_upload = self.run_remote(
                    ["mktemp", tempfile_template, ])
                if upload_file:
                    self.transfer(source, destination_upload)
                code.append('rm -rf {}'.format(destination))
                code.append('mv {} {}'.format(destination_upload, destination))

        if state_should in ('present', 'exists', 'pre-exists', ):
            for attribute in ('group', 'owner', 'mode', ):
                if attribute in self.parameters:
                    value_should = self.get_parameter(attribute)
                    if attribute == 'mode':
                        value_should = re.sub('^0', '', value_should)
                    stat_file = self.get_explorer_file('stat')
                    value_is = self.get_attribute(stat_file, attribute,
                                                  value_should)
                    if set_attributes or value_should != value_is:
                        fire_onchange = True
                        code.append(self.set_attribute(attribute,
                                                       value_should,
                                                       destination))
        elif state_should == 'absent':
            if typeis == 'file':
                code.append('rm -f {}'.format(destination))
                self.send_message('remove')
                fire_onchange = True
        else:
            self.die('Unknown state {}'.format(state_should))

        if fire_onchange:
            onchange = self.get_parameter('onchange')
            if onchange:
                code.append(onchange)

        return "\n".join(code)

    def get_args_parser(self):
        parser = argparse.ArgumentParser(add_help=False,
                                         argument_default=argparse.SUPPRESS)
        parser.add_argument('--state', dest='state', action='store',
                            required=False, default='present')
        for param in ('group', 'mode', 'owner', 'source', 'onchange'):
            parser.add_argument('--' + param, dest=param, action='store',
                                required=False, default=None)

        parser.add_argument("object_id", nargs=1)
        return parser
