# GNU Solfege - eartraining for GNOME
# Copyright (C) 2000, 2001, 2002  Tom Cato Amundsen
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import time, os, pickle
import utils
import configureoutput

STATISTICS_SAVE_DIR = os.path.join(os.path.expanduser('~'),
       '.solfege%s.%s' % (configureoutput.MAJOR_VERSION, configureoutput.MINOR_VERSION))
if not os.path.exists(STATISTICS_SAVE_DIR):
    os.mkdir(STATISTICS_SAVE_DIR)

YEAR = 0
MONTH = 1
DAY = 2
HOURS = 3
MINUTES = 4
SECONDS = 5
WEEKDAY = 6
JULIANDAY = 7

class AbstractStatistics:
    def __init__(self, teacher):
        self.m_t = teacher
        self.m_session_stat = {}
        self.m_today_stat = {}
        self.m_last7_stat = {}
        self.m_total_stat = {}
        self.m_dicts = {'session' : self.m_session_stat,
                        'today'   : self.m_today_stat,
                        'last7'   : self.m_last7_stat,
                        'total'   : self.m_total_stat}
        self.m_savepath = os.path.join(STATISTICS_SAVE_DIR, self.m_t.m_exname)
        if not os.path.exists(self.m_savepath):
            os.mkdir(self.m_savepath)
    def _add(self, question, answer):
        for D in [self.m_session_stat, self.m_today_stat,
                  self.m_last7_stat, self.m_total_stat]:
            if not D.has_key(question):
                D[question] = {}
            if not D[question].has_key(answer):
                D[question][answer] = 0
            D[question][answer] = D[question][answer] + 1
    def add_correct(self, answer):
        self._add(answer, answer)
    def add_wrong(self, question, answer):
        self._add(question, answer)
    def merge_stat_dicts(self, A, B):
        "Add content of B to A"
        for k in B.keys():
            if not A.has_key(k):
                A[k] = {}
            for n in B[k].keys():
                if not A[k].has_key(n):
                    A[k][n] = 0
                A[k][n] = A[k][n] + B[k][n]
        return A
    def load_statistics(self, datadir):
        for filename in os.listdir(datadir):
            t = int(filename)
            lt = time.localtime(t)
            f = open(os.path.join(datadir, filename), 'r')
            D = pickle.load(f)
            f.close()
            now = int(time.time())
            lt_today = time.localtime(time.time())
            if lt[YEAR] == lt_today[YEAR] and \
                    lt[JULIANDAY] == lt_today[JULIANDAY]:
                self.m_today_stat = self.merge_stat_dicts(self.m_today_stat, D)
            if now - t < 60*60*24*7: # 7 days
                self.m_last7_stat = self.merge_stat_dicts(self.m_last7_stat, D)
            self.m_total_stat = self.merge_stat_dicts(self.m_total_stat, D)
    def get(self):
        """Will return a 0 <= value <= 1.0 that say how many percent is
        correct in this session
        """
        c = t = 0
        for k in self.m_session_stat.keys():
            if self.m_session_stat[k].has_key(k):
                c = c + self.m_session_stat[k][k]
            t = t + self.get_num_guess(self.m_session_stat, k)
        if t > 0:
            return 1.0 * c / t
        else:
            return 0.0
    def display(self):
        print
        v = self.m_session_stat.keys()
        v.sort()
        for x in v:
            print x, self.m_session_stat[x]
    def get_keys(self, all=0):
        """
        by default it returns the keys for all questions that have
        been asked. If 'all' is true, it also includes the keys for
        all the wrong answers.
        """
        keys = []
        for st in self.m_session_stat, self.m_today_stat, self.m_last7_stat, self.m_total_stat:
            for k in st.keys():
                if k not in keys:
                    keys.append(k)
                if all:
                    for wk in self.m_total_stat[k].keys():
                        if wk not in keys:
                            keys.append(wk)
        keys.sort()
        return keys
    def get_num_guess(self, st, key):
        if not st.has_key(key):
            return 0
        t = 0
        for i in st[key].keys():
            t = t + st[key][i]
        return t
    def get_percentage_correct(self, st, key):
        """
        This was added to be used for harmonic-intervall.
        """
        if not st.has_key(key):
            return 0.0
        if st[key].has_key(key):
            num_correct = st[key][key]
        else:
            num_correct = 0
        total = 0
        for n in st[key].keys():
            total = total + st[key][n]
        return num_correct * 100.0 / total
    def key_to_pretty_name(self, k):
        return k
    def get_label_style(self):
        return 'normal'
    def reset_session(self):
        self.m_session_stat = {}


class Statistics(AbstractStatistics):
    def __init__(self, teacher):
        AbstractStatistics.__init__(self, teacher)
        self.load_statistics(self.m_savepath)
    def save_data(self):
        if self.m_session_stat:
            f = open(os.path.join(self.m_savepath, str(int(time.time()))), 'w')
            pickle.dump(self.m_session_stat, f)
            f.close()


class LessonStatistics(AbstractStatistics):
    def __init__(self, teacher):
        AbstractStatistics.__init__(self, teacher)
        self.m_cur_collection = self.m_cur_file = None
        self.lessonfile_changed(self.m_t.get_string('lessoncollection'),
                                self.m_t.get_string('lessonfile'))
    def get_label_style(self):
        return self.m_t.m_P.header.labelformat
    def lessonfile_changed(self, new_collection, new_file):
        if not new_file:
            return
        if self.m_cur_file and self.m_session_stat != {}:
            self.save_data()

        self.m_session_stat = {}
        self.m_today_stat = {}
        self.m_last7_stat = {}
        self.m_total_stat = {}
        self.m_cur_collection = new_collection
        self.m_cur_file = new_file
        self.create_statistics_dir()

        # if the lessonfile has changed, we have to
        # delete all statistics just to be save.
        if self.get_hash_of_statistics() != self.get_hash_of_lessonfile():
            p = os.path.join(self.m_savepath,
                             self.m_cur_collection,
                             self.m_cur_file)
            if os.path.isfile("%s_hash" % p):
                os.remove("%s_hash" % p)
            for f in os.listdir(p):
                os.remove(os.path.join(p, f))
        self.load_statistics(os.path.join(self.m_savepath,
                                          self.m_cur_collection,
                                          self.m_cur_file))
    def save_data(self):
        if self.m_session_stat == {}:
            return
        #save the hashvalue for the lessonfile this statistics was made with
        f = open(os.path.join(self.m_savepath,
                              self.m_cur_collection,
                              '%s_hash' % self.m_cur_file), 'w')
        f.write(str(self.get_hash_of_lessonfile()))
        f.close()
        f = open(os.path.join(self.m_savepath,
                              self.m_cur_collection,
                              self.m_cur_file,
                              str(int(time.time()))), 'w')
        pickle.dump(self.m_session_stat, f)
        f.close()
    def create_statistics_dir(self):
        dir = os.path.join(self.m_savepath, self.m_cur_collection)
        if not os.path.exists(dir):
            os.mkdir(dir)

        dir = os.path.join(dir, self.m_cur_file)
        if not os.path.exists(dir):
            os.mkdir(dir)
    def get_hash_of_statistics(self):
        # !wrong function name!
        # get the hash for the content of the lessonfile that was used last
        # time statistics was saved
        if os.path.isfile(os.path.join(self.m_savepath,
                                       self.m_cur_collection,
                                       '%s_hash' % self.m_cur_file)):
            s = open(os.path.join(self.m_savepath,
                                         self.m_cur_collection,
                                         '%s_hash' % self.m_cur_file)).read()
            try:
                return int(s)
            except:
                return 0
        else:
            return 0
    def get_hash_of_lessonfile(self):
        return hash(open(os.path.expanduser(os.path.join(
            self.m_t.get_string('lessoncollections/%s' % self.m_cur_collection),
            self.m_cur_file))).read())


class IntervallStatistics(Statistics):
    def key_to_pretty_name(self, key):
        return utils.int_to_intervallname(key, 1, 1)

class HarmonicIntervallStatistics(Statistics):
    def key_to_pretty_name(self, key):
        return utils.int_to_intervallname(key, 1, 0)
