# -*- encoding: utf-8 -*-
#   Copyright 2008 Agile42 GmbH, Berlin (Germany)
#   Copyright 2007 Andrea Tomasini <andrea.tomasini__at__agile42.com>
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#   
#   Author: 
#       - Andrea Tomasini <andrea.tomasini__at__agile42.com>
#       - Felix Schwarz <felix.schwarz__at__agile42.com>

from datetime import datetime, timedelta
import unittest

from trac.util.datefmt import utc

from agilo.api.controller import ValueObject
from agilo.scrum.team import TeamController
from agilo.utils import Type, Key
from agilo.utils.config import AgiloConfig
from agilo.utils.days_time import now
from agilo.test import TestEnvHelper


class TeamControllerTest(unittest.TestCase):
    """Tests the TeamController and all the Commands in it"""
    def setUp(self):
        """initalize and environment, and a controller instance"""
        self.teh = TestEnvHelper()
        self.env = self.teh.get_env()
        self.controller = TeamController(self.teh.get_env())
        self.sprint = self.teh.create_sprint('TestSprint', team='A-Team')
        self.s1 = self.teh.create_ticket(Type.USER_STORY, 
                                         props={Key.STORY_POINTS: '13',
                                                Key.SPRINT: 'TestSprint'})
        self.s2 = self.teh.create_ticket(Type.USER_STORY, 
                                         props={Key.STORY_POINTS: '13',
                                                Key.SPRINT: 'TestSprint'})
        self.s3 = self.teh.create_ticket(Type.USER_STORY, 
                                         props={Key.STORY_POINTS: '13',
                                                Key.SPRINT: 'TestSprint',
                                                Key.STATUS: 'closed'})
        
    def testCalculateVelocityCommand(self):
        """Tests the calculate velocity command"""
        cmd_calc_velocity = TeamController.CalculateTeamVelocityCommand(self.env,
                                                                        sprint=self.sprint)
        velocity = self.controller.process_command(cmd_calc_velocity)
        # Now velocity is the actual, so should be 13 only the closed story
        self.assertEqual(13, velocity)
        # Now check the estimated velocity, setting estimated to true in the command
        cmd_calc_velocity.estimated = True
        est_velocity = self.controller.process_command(cmd_calc_velocity)
        self.assertEqual(39, est_velocity)
    
    def testStoreAndRetriveVelocityCommands(self):
        """Tests the store and retrive of the team velocity from the metrics"""
        self.assertEqual('A-Team', self.sprint.team.name)
        cmd_store_velocity = TeamController.StoreTeamVelocityCommand(self.env,
                                                                     sprint=self.sprint)
        velocity = self.controller.process_command(cmd_store_velocity)
        self.assertEqual(13, velocity)
        # now check if it has been stored
        cmd_get_velocity = TeamController.GetStoredTeamVelocityCommand(self.env,
                                                                       sprint=self.sprint)
        metrics_velocity = self.controller.process_command(cmd_get_velocity)
        self.assertEqual(velocity, metrics_velocity)
        # now the estimated
        cmd_store_velocity.estimated = True
        cmd_get_velocity.estimated = True
        est_velocity = self.controller.process_command(cmd_store_velocity)
        self.assertEqual(39, est_velocity)
        metrics_est_velocity = self.controller.process_command(cmd_get_velocity)
        self.assertEqual(est_velocity, metrics_est_velocity)
    
    def testDailyCapacityForTeamCommand(self):
        """Tests the calculation of the Daily capacity of a team for a Sprint"""
        cmd_daily_capacity = TeamController.CalculateDailyCapacityCommand(self.env,
                                                                          #team='A-Team',
                                                                          sprint=self.sprint)
        capacity = self.controller.process_command(cmd_daily_capacity)
        # at: this may still fail given the normalization done by the 
        # normalise_date method, used by the Sprint to set end date and
        # start date.
        days = (self.sprint.end - self.sprint.start).days + 1 # extremes are included
        self.assertEqual(days, len(capacity))
        self.assertEqual([0] * days, capacity)
    
    def sprints_can_start_and_end_anytime(self):
        config = AgiloConfig(self.env)
        config.change_option('sprints_can_start_or_end_on_weekends', True, section='agilo-general')
        config.save()
        config.reload()
    
    def test_can_calculate_capacity_per_day_for_team(self):
        self.sprints_can_start_and_end_anytime()
        self.sprint.start = datetime(2009, 8, 1, 00, 00, tzinfo=utc)
        self.sprint.end = datetime(2009, 8, 10, 23, 59, tzinfo=utc)
        self.sprint.save()
        self.teh.create_member('Foo', self.sprint.team)
        
        cmd_daily_capacity = TeamController.CalculateDailyCapacityCommand(self.env, sprint=self.sprint, team=self.sprint.team)
        capacity_per_day = self.controller.process_command(cmd_daily_capacity)
        self.assertEqual(10, len(capacity_per_day))
        self.assertEqual([0, 0,   6, 6, 6, 6, 6, 0, 0,   6], capacity_per_day)
        self.assertEqual(36, sum(capacity_per_day))
    
    def testGetTeamCommandReturnsMembersAsDict(self):
        team = self.teh.create_team('Testteam')
        self.teh.create_member('foo', team)
        cmd = TeamController.GetTeamCommand(self.env, team=team.name)
        value_team = TeamController(self.env).process_command(cmd)
        
        members = value_team.members
        self.assertEqual(1, len(members))
        self.assertTrue(isinstance(members[0], ValueObject))
    
    def test_confirm_commitment_uses_current_remaining_time(self):
        self.sprint.start = now() - timedelta(hours=2)
        self.sprint.save()
        task_properties = {Key.REMAINING_TIME: '7', Key.SPRINT: self.sprint.name}
        self.teh.create_ticket(Type.TASK, props=task_properties)
        
        cmd = TeamController.CalculateAndStoreTeamCommitmentCommand(self.env, sprint=self.sprint, team=self.sprint.team)
        commitment = TeamController(self.env).process_command(cmd)
        self.assertEqual(7, commitment)



if __name__ == '__main__':
    from agilo.test.testfinder import run_unit_tests
    run_unit_tests(__file__)
