import gzip
from pathlib import Path
import sys
from utils.input_output import load_yaml
from chardet.universaldetector import UniversalDetector


# ClassName(object) --> only in Python2 necessary
# inherit from object
class ProteomicSearchResultReaderBaseClass:
    """
    Base class for reading the result files of proteomic search engines.
    Child classes must implement the method 'read_file_into_dataframe'.
    This method must return a dataframe with the following columns:
      - 'proteins': each field contains a list of protein accessions
      - 'sample': sample name
      - 'quant': quantification values
    """
    mandatory_style_fields = ['proteins_sep', 'field_sep', 'sample_cols', 'proteins_col', 'quant_col']

    def __init__(self, result_table, f_style, required_sample_descriptors):
        self.result_table = result_table
        self.f_style = f_style
        self.required_sample_descriptors = required_sample_descriptors
        self.style_dict = load_yaml(self.f_style)
        self.check_style()

    def check_style(self):
        # style checks
        missing_tags = [x for x in self.mandatory_style_fields if x not in self.style_dict]
        if missing_tags:
            sys.exit('input style error in ' + self.f_style + ":\nmissing information:\n" + ", ".join(missing_tags))
        if self.style_dict['proteins_sep'] == self.style_dict['field_sep']:
            raise ValueError("'proteins_sep' and 'field_sep' must be different but are both: '{}'"
                             .format(self.style_dict['proteins_sep']))


class InputFile(object):
    """
    Base class for providing input file related informations:
      - encoding: file encoding
    """
    def __init__(self, fname):
        self.fname = fname
        self._encoding = None

    @property
    def encoding(self):
        if not self._encoding:
            detector = UniversalDetector()
            open_func = gzip.open if Path(self.fname).suffix == ".gz" else open
            with open_func(self.fname, "rb") as handle:
                for line in handle:
                    detector.feed(line)
                    if detector.done:
                        break
                detector.close()
            self._encoding = detector.result['encoding']
        return self._encoding
