#####################################################################
# -*- coding: iso-8859-1 -*-                                        #
#                                                                   #
# Frets on Fire                                                     #
# Copyright (C) 2006 Sami Kyöstilä                                  #
#               2008 Alarian                                        #
#               2008 myfingershurt                                  #
#               2008 Glorandwarf                                    #
#               2008 Spikehead777                                   #
#               2008 QQStarS                                        #
#               2008 Blazingamer                                    #
#               2008 evilynux <evilynux@gmail.com>                  #
#               2008 fablaculp                                      #
#               2009 akedrou                                        #
#                                                                   #
# 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., 51 Franklin Street, Fifth Floor, Boston,        #
# MA  02110-1301, USA.                                              #
#####################################################################

from fofix.core.Language import _
from fofix.game import Song
from fofix.core import Log
from fofix.core import Config

HANDICAPS = [.75, 1.0, .8, .9, .75, .8, 1.05, 1.1, 1.03, 1.02, 1.01, .95, .9, .85, .7, .95, 0.0, .5, .7, .7]
HANDICAP_NAMES = [_("Auto Kick Bass"), _("Medium Assist Mode"), _("Easy Assist Mode"), _("Jurgen Played!"), \
                  _("Effects Saved SP"), _("All Tapping"), _("HOPO Frequency: Most"), _("HOPO Frequency: Even More"), \
                  _("HOPO Frequency: More"), _("HOPO Frequency: Less"), _("HOPO Frequency: Least"), _("HOPO Disabled!"), \
                  _("Hit Window: Tightest!"), _("Hit Window: Tight!"), _("Hit Window: Wider"), _("Hit Window: Widest"), \
                  _("Two Note Chords"), _("No Fail Mode"), "Scalable Cheat", _("Sloppy Mode!")]
SCALABLE_NAMES = [_("Song Slowdown"), _("Early Hit Window Adjustment")]
SCORE_MULTIPLIER = [0, 10, 20, 30]
BASS_GROOVE_SCORE_MULTIPLIER = [0, 10, 20, 30, 40, 50]

class ScoreCard(object):
    def __init__(self, instrument, coOpType = False):
        self.coOpType = coOpType
        logClassInits = Config.get("game", "log_class_inits")
        if logClassInits == 1:
            Log.debug("ScoreCard class init...")
        self.starScoring = Config.get("game", "star_scoring")
        self.updateOnScore = Config.get("performance", "star_score_updates")
        self.avMult = 0.0
        self.hitAccuracy = 0.0
        self.score  = 0
        if instrument == [5]:
            self.baseScore = 0
        else:
            self.baseScore = 50
        self.notesHit = 0
        self.percNotesHit = 0
        self.notesMissed = 0
        self.instrument = instrument # 0 = Guitar, 2 = Bass, 4 = Drum
        self.bassGrooveEnabled = False
        self.hiStreak = 0
        self._streak  = 0
        self.cheats = []
        self.scalable = []
        self.earlyHitWindowSizeHandicap = 1.0
        self.handicap = 0
        self.longHandicap  = ""
        self.handicapValue = 100.0
        self.totalStreakNotes = 0
        self.totalNotes = 0
        self.totalPercNotes = 0
        self.cheatsApply = False
        self.stars = 0
        self.starRatio = 0.0
        self.star = [0 for i in range(7)]
        if self.starScoring == 1: #GH-style (mult thresholds, hit threshold for 5/6 stars)
            self.star[5] = 2.8
            self.star[4] = 2.0
            self.star[3] = 1.2
            self.star[2] = 0.4
            self.star[1] = 0.2 #akedrou - GH may start with 1 star, but why do we need to?
            self.star[0] = 0.0
        elif self.starScoring > 1: #RB-style (mult thresholds, optional 100% gold star)
            if self.starScoring == 4:
                if self.instrument[0] == Song.BASS_PART and not self.coOpType:
                    self.star[6] = 6.78
                    self.star[5] = 4.62
                    self.star[4] = 2.77
                    self.star[3] = 0.90
                    self.star[2] = 0.50
                    self.star[1] = 0.21
                    self.star[0] = 0.0
                else:
                    if self.instrument[0] == Song.DRUM_PART and not self.coOpType:
                        self.star[6] = 4.29
                    elif self.instrument[0] == Song.VOCAL_PART and not self.coOpType:
                        self.star[6] = 4.18
                    else:
                        self.star[6] = 4.52
                    self.star[5] = 3.08
                    self.star[4] = 1.85
                    self.star[3] = 0.77
                    self.star[2] = 0.46
                    self.star[1] = 0.21
                    self.star[0] = 0.0
            else:
                self.star[5] = 3.0
                self.star[4] = 2.0
                self.star[3] = 1.0
                self.star[2] = 0.5
                self.star[1] = 0.25
                self.star[0] = 0.0
                if self.coOpType:
                    self.star[6] = 4.8
                elif self.instrument[0] == Song.BASS_PART: # bass
                    self.star[6] = 4.8
                elif self.instrument[0] == Song.DRUM_PART: # drum
                    self.star[6] = 4.65
                else:
                    self.star[6] = 5.3
        else: #hit accuracy thresholds
            self.star[6] = 100
            self.star[5] = 95
            self.star[4] = 75
            self.star[3] = 50
            self.star[2] = 30
            self.star[1] = 10
            self.star[0] = 0

        self.endingScore = 0    #MFH
        self.endingStreakBroken = False   #MFH
        self.endingAwarded = False    #MFH
        self.lastNoteEvent = None    #MFH
        self.lastNoteTime  = 0.0
        self.freestyleWasJustActive = False  #MFH


    def reset(self):
        self.avMult = 0.0
        self.hitAccuracy = 0.0
        self.score  = 0
        self.notesHit = 0
        self.notesMissed = 0
        self.hiStreak = 0
        self._streak = 0
        self.cheats = []
        self.handicap = 0
        self.longHandicap  = ""
        self.handicapValue = 100.0
        self.cheatsApply = False
        self.stars = 0
        self.starRatio = 0.0
        self.endingScore = 0    #MFH
        self.endingStreakBroken = False   #MFH
        self.endingAwarded = False    #MFH
        self.freestyleWasJustActive = False  #MFH

    def getStarScores(self, tempExtraScore = 0):
        if self.updateOnScore == 1 and self.instrument[0] != Song.VOCAL_PART:
            avMult = float(self.score+tempExtraScore) / float(self.totalNotes * self.baseScore)
        else:
            avMult = self.avMult
        if self.starScoring == 1: #GH-style
            if self.hitAccuracy == 100.0 and self.hiStreak == self.totalStreakNotes and not self.cheatsApply:
                self.stars = 7
                self.starRatio = 0
                return 7
            if self.hitAccuracy == 100.0 and not self.cheatsApply:
                self.stars = 6
                self.starRatio = 0
                return 6
            elif (self.hitAccuracy >= 90.0 and not self.cheatsApply) or avMult >= self.star[5]:
                self.stars = 5
                self.starRatio = 0
                return 5
            else:
                for i in range(4, -1, -1):
                    if avMult >= self.star[i]:
                        part = avMult - self.star[i]
                        partPct = part / (self.star[i+1] - self.star[i])
                        self.stars = i
                        self.starRatio = partPct
                        return i
        elif self.starScoring >= 2: #RB-style and RB+GH (and RB2)
            hundredGold = True
            if self.starScoring == 2:
                hundredGold = False
            if hundredGold and self.hitAccuracy == 1.0 and self.hiStreak == self.totalStreakNotes and not self.cheatsApply:
                self.stars = 7
                self.starRatio = 0
                return 7
            if (self.hitAccuracy == 1.0 and hundredGold) or avMult > self.star[6]:
                self.stars = 6
                self.starRatio = 0
                return 6
            elif avMult >= self.star[5]:
                self.stars = 5
                self.starRatio = 0
                return 5
            else:
                for i in range(4, -1, -1):
                    if avMult >= self.star[i]:
                        part = avMult - self.star[i]
                        partPct = part / (self.star[i+1] - self.star[i])
                        self.stars = i
                        self.starRatio = partPct
                        return i
        else: #FoF
            if self.hitAccuracy == 1.0 and self.hiStreak == self.totalStreakNotes and not self.cheatsApply:
                self.stars = 7
                self.starRatio = 0
                return 7
            if self.hitAccuracy == self.star[6]:
                self.stars = 6
                self.starRatio = 0
                return 6
            elif self.hitAccuracy >= self.star[5]:
                self.stars = 5
                self.starRatio = 0
                return 5
            else:
                for i in range(4, -1, -1):
                    if self.hitAccuracy >= self.star[i]:
                        part = self.hitAccuracy - self.star[i]
                        partPct = part / (self.star[i+1] - self.star[i])
                        self.stars = i
                        self.starRatio = partPct
                        return i

    def updateAvMult(self):
        try:
            self.hitAccuracy = (float(self.notesHit) / float(self.totalStreakNotes) ) * 100.0
        except ZeroDivisionError:
            self.hitAccuracy = 0.0
        try:
            if self.instrument[0] == Song.VOCAL_PART and not self.coOpType:
                self.avMult = float(self.score)/float(self.baseScore)
            else:
                self.avMult      = self.score/float(self.totalNotes*self.baseScore)
        except ZeroDivisionError:
            self.avMult      = 1.0

    def updateHandicapValue(self):
        self.handicapValue = 100.0
        slowdown = Config.get("audio","speed_factor")
        earlyHitHandicap      = 1.0 #self.earlyHitWindowSizeHandicap #akedrou - replace when implementing handicap.
        for j in range(len(HANDICAPS)):
            if (self.handicap>>j)&1 == 1:
                if j == 1: #scalable
                    if slowdown != 1:
                        if slowdown < 1:
                            cut = (100.0**slowdown)/100.0
                        else:
                            cut = (100.0*slowdown)/100.0
                        self.handicapValue *= cut
                    if earlyHitHandicap != 1.0:
                        self.handicapValue *= earlyHitHandicap
                else:
                    self.handicapValue *= HANDICAPS[j]

    def getStreak(self):
        return self._streak

    def setStreak(self, value):
        self._streak = value
        self.hiStreak = max(self._streak, self.hiStreak)

    streak = property(getStreak, setStreak)

    def addScore(self, score):
        self.score += score * self.getScoreMultiplier()

    def addEndingScore(self):
        self.score += self.endingScore

    def getScoreMultiplier(self):
        if self.instrument == [Song.BASS_PART] and self.bassGrooveEnabled:    #myfingershurt: bass groove
            try:
                return BASS_GROOVE_SCORE_MULTIPLIER.index((self.streak / 10) * 10) + 1
            except ValueError:
                return len(BASS_GROOVE_SCORE_MULTIPLIER)
        elif self.instrument == [Song.VOCAL_PART]:
            return min(self.streak + 1, 4)
        else:
            try:
                return SCORE_MULTIPLIER.index((self.streak / 10) * 10) + 1
            except ValueError:
                return len(SCORE_MULTIPLIER)

class Rockmeter:
    pass # future breaking out of rockmeter can likely go here. Scorekeeper seems fitting.
