import numpy as SP
import subprocess, sys, os.path
from itertools import *
from pysnptools.pysnptools.altset_list import *
import pandas as pd
import logging
from snpreader import SnpReader
from snpdata import SnpData

class _Subset(SnpReader):

    def __init__(self, internal, iid_indexer, sid_indexer):
        '''
        an indexer can be:
             an integer i (same as [i])
             a slice
             a list of integers
             a list of booleans
        '''
        self._internal = internal
        self._iid_indexer = SnpReader._make_sparray_or_slice(iid_indexer)
        self._sid_indexer = SnpReader._make_sparray_or_slice(sid_indexer)

    _ran_once = False

    def __repr__(self):
        s = "{0}[{1},{2}]".format(self._internal,self.nice_string(self._iid_indexer),self.nice_string(self._sid_indexer))
        return s

    _slice_format = {(False,False,False):":",
                     (False,False,True):"::{2}",
                     (False,True,False):":{1}",
                     (False,True,True):":{1}:{2}",
                     (True,False,False):"{0}:",
                     (True,False,True):"{0}::{2}",
                     (True,True,False):"{0}:{1}",
                     (True,True,True):"{0}:{1}:{2}"}

    def nice_string(self, some_slice):
        if isinstance(some_slice,slice):
            return self._slice_format[(some_slice.start is not None, some_slice.stop is not None, some_slice.step is not None)].format(some_slice.start, some_slice.stop, some_slice.step)
        elif len(some_slice) == 1:
            return str(some_slice[0])
        elif len(some_slice) < 10:
            return "[{0}]".format(",".join([str(i) for i in some_slice]))
        else:
            return "[{0},...]".format(",".join([str(i) for i in some_slice[:10]]))

    def copyinputs(self, copier):
        self._internal.copyinputs(copier)

    @property
    def iid(self):
        self.run_once()
        return self._iid

    @property
    def sid(self):
        self.run_once()
        return self._sid

    @property
    def pos(self):
        self.run_once()
        return self._pos

    def read(self, order='F', dtype=SP.float64, force_python_only=False, view_ok=False):
        if view_ok and _Subset._is_all_slice(self._iid_indexer) and _Subset._is_all_slice(self._sid_indexer): #!!!cmk04072014 regression test
            return self
        else:
            return SnpReader.read(self, order, dtype, force_python_only, view_ok)


    def _read(self, iid_index_or_none, sid_index_or_none, order, dtype, force_python_only):
        self.run_once()

        composed_iid_index_or_none = self.compose_indexer_with_index_or_none(self._internal.iid_count, self._iid_indexer, self.iid_count, iid_index_or_none)
        composed_sid_index_or_none = self.compose_indexer_with_index_or_none(self._internal.sid_count, self._sid_indexer, self.sid_count, sid_index_or_none)

        val = self._internal._read(composed_iid_index_or_none, composed_sid_index_or_none, order, dtype, force_python_only)

        return val

    def run_once(self):
        if self._ran_once:
            return

        self._ran_once = True
        self._iid = self._internal.iid[self._iid_indexer]
        self._sid = self._internal.sid[self._sid_indexer]
        self._pos = self._internal.pos[self._sid_indexer]

    @staticmethod
    def compose_indexer_with_index_or_none(countA, indexerA, countB, index_or_noneB):
        if _Subset._is_all_slice(indexerA):
            return index_or_noneB

        indexA = SnpReader._make_sparray_from_sparray_or_slice(countA, indexerA)

        if _Subset._is_all_slice(index_or_noneB):
            return indexA

        indexAB = indexA[index_or_noneB]

        return indexAB
