############################################################################
#   Copyright (C) 2005 by Reithinger GmbH
#   mreithinger@web.de
#
#   This file is part of faces.
#                                                                         
#   faces 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.
#
#   faces 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 faces.pcalendar as pcal
import matplotlib.cbook as cbook
import datetime
import sys


class TimeScale(object):
    def __init__(self, calendar):
        self.data_calendar = calendar
        self._create_chart_calendar()
        self.now = self.to_num(self.data_calendar.now)
                

    def to_datetime(self, xval):
        return xval.to_datetime()


    def to_num(self, date):
        return self.chart_calendar.WorkingDate(date)


    def is_free_slot(self, value):
        dt1 = self.chart_calendar.to_starttime(value)
        dt2 = self.data_calendar.to_starttime\
              (self.data_calendar.from_datetime(dt1))
        return dt1 != dt2


    def is_free_day(self, value):
        dt1 = self.chart_calendar.to_starttime(value)
        dt2 = self.data_calendar.to_starttime\
              (self.data_calendar.from_datetime(dt1))
        return dt1.date() != dt2.date()


    def _create_chart_calendar(self):
        dcal = self.data_calendar
        ccal = self.chart_calendar = pcal.Calendar()
        ccal.minimum_time_unit = 1

        #pad worktime slots of calendar (all days should be equally long)
        slot_sum = lambda slots: sum(map(lambda slot: slot[1] - slot[0], slots))
        day_sum = lambda day: slot_sum(dcal.get_working_times(day))
        
        max_work_time = max(map(day_sum, range(7)))

        #working_time should have 2/3
        sum_time = 3 * max_work_time / 2

        #now create timeslots for ccal
        def create_time_slots(day):
            src_slots = dcal.get_working_times(day)
            slots = [0, src_slots, 24*60]
            slots = tuple(cbook.flatten(slots))
            slots = zip(slots[:-1], slots[1:])

            #balance non working slots
            work_time = slot_sum(src_slots)
            non_work_time = sum_time - work_time

            non_slots = filter(lambda s: s not in src_slots, slots)
            non_slots = map(lambda s: (s[1] - s[0], s), non_slots)
            non_slots.sort()

            slots = []
            i = 0
            for l, s in non_slots:
                delta = non_work_time / (len(non_slots) - i)
                delta = min(l, delta)
                non_work_time -= delta
                slots.append((s[0], s[0] + delta))
                i += 1

            slots.extend(src_slots)
            slots.sort()
            return slots

        min_delta = sys.maxint
        for i in range(7):
            slots = create_time_slots(i)
            ccal.working_times[i] = slots
            min_delta = min(min_delta, min(map(lambda s: s[1] - s[0], slots)))

        ccal._recalc_working_time()

        self.slot_delta = min_delta
        self.day_delta = sum_time
        self.week_delta = ccal.week_time


_default_scale = TimeScale(pcal._default_calendar)
