from __future__ import (division, absolute_import, print_function,
                        unicode_literals)
from future import standard_library
from future.builtins import *

from .common import UnmatchedStepError, combined_match_dict, u
from copy import copy
from io import StringIO
import re
import yaml


class Step(object):

    def parse(self, step_set, toparse, start_index):
        raise NotImplementedError('Step subclasses must implement parse')

    def __call__(self, context, args):
        raise NotImplementedError('Step subclasses must implement __call__')


class RegexStep(Step):

    def __init__(self, regex, multiline=False):
        self.multiline = multiline
        self.regex = re.compile(regex)

    def parse(self, step_set, toparse, start_index):
        if self.multiline:
            return self.parse_multiline(toparse, start_index)
        else:
            return self.parse_line(toparse, start_index)

    def parse_multiline(self, toparse, start_index):
        match = self.regex.match(toparse, start_index)
        if match:
            match_dict = combined_match_dict(match)
            end = match.end()
            return (match_dict, self), end
        line = toparse[start_index:].split('\n', 1)[0]
        raise UnmatchedStepError(line)

    def parse_line(self, toparse, start_index):
        end = len(toparse)
        line_end = toparse.find('\n', start_index)
        if line_end == -1:
            line_end = end
        line = toparse[start_index:line_end]
        match = self.regex.search(line)
        if match:
            match_dict = combined_match_dict(match)

            start = match.start()
            end = match.end()

            if start > 0:
                match_dict['prefix_content'] = line[:start]
            if end < len(line):
                match_dict['suffix_content'] = line[end:]

            return (match_dict, self), line_end + 1
        raise UnmatchedStepError(line)

    def __repr__(self):
        return '<{}.{} "{}">'.format(self.__class__.__module__,
                                     self.__class__.__name__,
                                     self.regex.pattern)


class RegexFuncStep(RegexStep):

    def __init__(self, regex, func, multiline=False):
        super(RegexFuncStep, self).__init__(regex, multiline)
        self.func = func

    def __call__(self, context, args):
        return self.func(context, args)

    @classmethod
    def make(cls, regex, multiline=False):
        """Decorator which wraps the specified regex and func in a
        RegexFuncStep instance
        """
        def make_inst(func):
            return cls(regex, func, multiline)

        return make_inst

    def __repr__(self):
        return '<{}.{} {}.{} "{}">'.format(
            self.__class__.__module__, self.__class__.__name__,
            self.func.__module__, self.func.__name__,
            self.regex.pattern)


class PrefixStep(RegexStep):

    """ A simple step which matches a regex and returns True

    For use with composite steps to require a prefix before another
    step. For example, to add a prefix before a YamlFuncStep.

    Defaults to multiline=True so it can match in the middle of a
    line.
    """

    def __init__(self, regex, multiline=True):
        super(PrefixStep, self).__init__(regex, multiline)

    def __call__(self, context, args):
        return True


class YamlStep(Step):

    def parse(self, step_set, toparse, start_index):
        step_io = StringIO(u(toparse))
        step_io.seek(start_index, 0)

        loader = yaml.Loader(step_io)
        try:
            val = loader.get_data()