#!/usr/bin/env python

""" MultiQC module to parse output from methylQA """

from __future__ import print_function
from collections import OrderedDict
import logging
import os
import re

from multiqc.plots import linegraph
from multiqc.modules.base_module import BaseMultiqcModule

# Initialise the logger
log = logging.getLogger(__name__)


class MultiqcModule(BaseMultiqcModule):
    def __init__(self):

        # Initialise the parent object
        super(MultiqcModule, self).__init__(
            name="methylQA",
            anchor="methylqa",
            target="methylQA",
            href="http://methylqa.sourceforge.net/",
            info=" - a methylation sequencing data quality assessment tool.",
        )

        # Find and load any methylQA reports
        self.methylqa_data = dict()
        self.methylqa_coverage_counts = dict()
        self.methylqa_coverage_percentages = dict()
        for f in self.find_log_files("methylQA"):
            self.parse_methylqa_logs(f)

        # Filter to strip out ignored sample names
        self.methylqa_data = self.ignore_samples(self.methylqa_data)

        if len(self.methylqa_data) == 0:
            raise UserWarning

        log.info("Found {} reports".format(len(self.methylqa_data)))

        # Write parsed report data to a file
        self.write_data_file(self.methylqa_data, "multiqc_methylQA")

        # Basic Stats Table
        self.methylqa_general_stats_table()

        # Alignment bar plot - only one section, so add to the module intro
        self.add_section(plot=self.methylqa_alignment_plot())

    def parse_methylqa_logs(self, f):

        # Get s_name from first input file if possible
        s_name = f["s_name"]
        if f["f"][0].startswith("files provided"):
            s_name = self.clean_s_name(os.path.basename(f["f"][0]), f)

        parsed_data = {}
        regexes = {
            "mappable_reads": r"uniquely mappable reads \(pair\):\s*(\d+)",
            "quality_failed": r"quality failed mapped reads \(pair\) in the bismark bam:\s*(\d+)",
            "oversized_reads": r"oversized mapped reads \(pair\) in the bismark bam:\s*(\d+)",
            "mapped_bases": r"total base of uniquely mapped reads \(pair\):\s*(\d+)",
            "coverage": r"total base of uniquely mapped reads \(pair\) cover genome base \(\d+\):\s*([\d\.]+)X",
            "CHG_count_meth": r"number of methylated C in CHG context \(was protected\):\s*(\d+)",
            "CHG_count_unmeth": r"number of not methylated C in CHG context \(was converted\):\s*(\d+)",
            "CHG_percent_meth": r"C->T convertion rate in CHG context:\s*([\d\.]+)%",
            "CHH_count_meth": r"number of methylated C in CHH context \(was protected\):\s*(\d+)",
            "CHH_count_unmeth": r"number of not methylated C in CHH context \(was converted\):\s*(\d+)",
            "CHH_percent_meth": r"C->T convertion rate in CHH context:\s*([\d\.]+)%",
            "CG_count_meth": r"number of methylated C in CpG context \(was protected\):\s*(\d+)",
            "CG_count_unmeth": r"number of not methylated C in CpG context \(was converted\):\s*(\d+)",
            "CG_percent_meth": r"C->T convertion rate in CpG context:\s*([\d\.]+)%",
            "CN_count_meth": r"number of methylated C in Unknown context \(was protected\):\s*(\d+)",
            "CN_count_unmeth": r"number of not methylated C in Unknown context \(was converted\):\s*(\d+)",
            "CN_percent_meth": r"C->T convertion rate in Unknown context:\s*([\d\.]+)%",
        }
        for k, r in regexes.items():
            match = re.search(r, f["f"])
            if match:
                parsed_data[k] = float(match.group(1))

        # Parse the coverage histogram
        hist = False
        for l in f["f"].split(os.linesep):
            if hist is not False:
                try:
                    s = l.split()
                    hist["counts"][s[0]] = int(s[1])
                    hist["percentages"][s[0]] = float(s[2])
                except IndexError:
                    break
            if re.search(r"Times covered\s+Count\s+Percent\s+", l):
                hist = {"counts": OrderedDict(), "percentages": OrderedDict()}
        if hist is not False and len(hist) > 0:
            self.methylqa_coverage_counts[s_name] = hist["counts"]
            self.methylqa_coverage_percentages[s_name] = hist["percentages"]

        if len(parsed_data) > 0:
            if s_name in self.methylqa_data:
                log.debug("Duplicate sample name found! Overwriting: {}".format(s_name))
            self.add_data_source(f, s_name)
            self.methylqa_data[s_name] = parsed_data

    def methylqa_general_stats_table(self):
        """Take the parsed stats from the methylQA report and add it to the
        basic stats table at the top of the report"""

        headers = OrderedDict()
        headers["coverage"] = {"title": "Fold Coverage", "min": 0, "suffix": "X", "scale": "YlGn"}
        self.general_stats_addcols(self.methylqa_data, headers)

    def methylqa_alignment_plot(self):
        """Make the HighCharts HTML to plot the alignment rates"""

        if len(self.methylqa_coverage_counts) == 0:
            return '<div class="alert alert-danger">No histogram data found.</div>'

        pconfig = {
            "id": "methylqa_coverage",
            "title": "methylQA: CpG Coverage",
            "categories": True,
            "ylab": "CpG Counts",
            "xlab": "Times covered",
            "ymin": 0,
            "data_labels": [
                {"name": "Counts", "ylab": "CpG Counts"},
                {"name": "Percentages", "ylab": "% CpGs", "ymax": 100},
            ],
        }
        return linegraph.plot([self.methylqa_coverage_counts, self.methylqa_coverage_percentages], pconfig)
