Don't allow the start date to be later than the end date. If it is, modify whichever...
[fpdb-dooglus.git] / pyfpdb / TourneySummary.py
blob826e07aa4a505bc9eac8289f5120d1ad42052255
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 #Copyright 2009-2011 Stephane Alessio
5 #This program is free software: you can redistribute it and/or modify
6 #it under the terms of the GNU Affero General Public License as published by
7 #the Free Software Foundation, version 3 of the License.
8 #
9 #This program is distributed in the hope that it will be useful,
10 #but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 #GNU General Public License for more details.
14 #You should have received a copy of the GNU Affero General Public License
15 #along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #In the "official" distribution you can find the license in agpl-3.0.txt.
18 """parses and stores summary sections from e.g. eMail or summary files"""
20 import L10n
21 _ = L10n.get_translation()
23 # TODO: check to keep only the needed modules
25 import re
26 import sys
27 import traceback
28 import logging
29 import os
30 import os.path
31 from decimal_wrapper import Decimal
32 import operator
33 import time,datetime
34 from copy import deepcopy
35 from Exceptions import *
37 import pprint
38 import DerivedStats
39 import Card
40 import Database
42 log = logging.getLogger("parser")
44 class TourneySummary(object):
46 ################################################################
47 # Class Variables
48 UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K', 'S':'s', 'C':'c', 'H':'h', 'D':'d'} # SAL- TO KEEP ??
49 LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'} # SAL- TO KEEP ??
50 SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''}
51 MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE', 'ha': 'HA'}
52 SITEIDS = {'Fulltilt':1, 'Full Tilt Poker':1, 'PokerStars':2, 'Everleaf':3, 'Win2day':4, 'OnGame':5, 'UltimateBet':6, 'Betfair':7, 'Absolute':8, 'PartyPoker':9, 'Winamax':14 }
55 def __init__(self, db, config, siteName, summaryText, builtFrom = "HHC"):
56 self.db = db
57 self.config = config
58 self.siteName = siteName
59 self.siteId = self.SITEIDS[siteName]
61 self.summaryText = summaryText
62 self.tourneyName = None
63 self.tourneyTypeId = None
64 self.tourneyId = None
65 self.startTime = None
66 self.endTime = None
67 self.tourNo = None
68 self.currency = None
69 self.buyin = 0
70 self.fee = 0
71 self.hero = None
72 self.maxseats = 0
73 self.entries = 0
74 self.speed = "Normal"
75 self.prizepool = 0 # Make it a dict in order to deal (eventually later) with non-money winnings : {'MONEY' : amount, 'OTHER' : Value ??}
76 self.buyInChips = 0
77 self.mixed = None
78 self.isRebuy = False
79 self.isAddOn = False
80 self.isKO = False
81 self.isMatrix = False
82 self.isShootout = False
83 self.matrixMatchId = None # For Matrix tourneys : 1-4 => match tables (traditionnal), 0 => Positional winnings info
84 self.matrixIdProcessed = None
85 self.subTourneyBuyin = None
86 self.subTourneyFee = None
87 self.rebuyChips = None
88 self.addOnChips = None
89 self.rebuyCost = None
90 self.addOnCost = None
91 self.totalRebuyCount = None
92 self.totalAddOnCount = None
93 self.koBounty = None
94 self.tourneyComment = None
95 self.players = []
96 self.isSng = False
97 self.isSatellite = False
98 self.isDoubleOrNothing = False
99 self.guarantee = None
100 self.added = None
101 self.addedCurrency = None
102 self.gametype = {'category':None, 'limitType':None}
103 self.comment = None
104 self.commentTs = None
106 # Collections indexed by player names
107 self.playerIds = {}
108 self.tourneysPlayersIds = {}
109 self.ranks = {}
110 self.winnings = {}
111 self.winningsCurrency = {}
112 self.rebuyCounts = {}
113 self.addOnCounts = {}
114 self.koCounts = {}
116 # currency symbol for this summary
117 self.sym = None
119 if builtFrom=="IMAP":
120 # Fix line endings?
121 pass
122 if self.db == None:
123 self.db = Database.Database(config)
125 self.parseSummary()
126 self.insertOrUpdate()
127 #end def __init__
129 def __str__(self):
130 #TODO : Update
131 vars = ( (_("SITE"), self.siteName),
132 (_("START TIME"), self.startTime),
133 (_("END TIME"), self.endTime),
134 (_("TOURNEY NAME"), self.tourneyName),
135 (_("TOURNEY NO"), self.tourNo),
136 (_("TOURNEY TYPE ID"), self.tourneyTypeId),
137 (_("TOURNEY ID"), self.tourneyId),
138 (_("BUYIN"), self.buyin),
139 (_("FEE"), self.fee),
140 (_("CURRENCY"), self.currency),
141 (_("HERO"), self.hero),
142 (_("MAXSEATS"), self.maxseats),
143 (_("ENTRIES"), self.entries),
144 (_("SPEED"), self.speed),
145 (_("PRIZE POOL"), self.prizepool),
146 (_("STARTING CHIP COUNT"), self.buyInChips),
147 (_("MIXED"), self.mixed),
148 (_("REBUY"), self.isRebuy),
149 (_("ADDON"), self.isAddOn),
150 (_("KO"), self.isKO),
151 (_("MATRIX"), self.isMatrix),
152 (_("MATRIX ID PROCESSED"), self.matrixIdProcessed),
153 (_("SHOOTOUT"), self.isShootout),
154 (_("MATRIX MATCH ID"), self.matrixMatchId),
155 (_("SUB TOURNEY BUY IN"), self.subTourneyBuyin),
156 (_("SUB TOURNEY FEE"), self.subTourneyFee),
157 (_("REBUY CHIPS"), self.rebuyChips),
158 (_("ADDON CHIPS"), self.addOnChips),
159 (_("REBUY COST"), self.rebuyCost),
160 (_("ADDON COST"), self.addOnCost),
161 (_("TOTAL REBUYS"), self.totalRebuyCount),
162 (_("TOTAL ADDONS"), self.totalAddOnCount),
163 (_("KO BOUNTY"), self.koBounty),
164 (_("TOURNEY COMMENT"), self.tourneyComment),
165 (_("SNG"), self.isSng),
166 (_("SATELLITE"), self.isSatellite),
167 (_("DOUBLE OR NOTHING"), self.isDoubleOrNothing),
168 (_("GUARANTEE"), self.guarantee),
169 (_("ADDED"), self.added),
170 (_("ADDED CURRENCY"), self.addedCurrency),
171 (_("COMMENT"), self.comment),
172 (_("COMMENT TIMESTAMP"), self.commentTs)
175 structs = ( (_("PLAYER IDS"), self.playerIds),
176 (_("PLAYERS"), self.players),
177 (_("TOURNEYS PLAYERS IDS"), self.tourneysPlayersIds),
178 (_("RANKS"), self.ranks),
179 (_("WINNINGS"), self.winnings),
180 (_("WINNINGS CURRENCY"), self.winningsCurrency),
181 (_("COUNT REBUYS"), self.rebuyCounts),
182 (_("COUNT ADDONS"), self.addOnCounts),
183 (_("NB OF KO"), self.koCounts)
185 str = ''
186 for (name, var) in vars:
187 str = str + "\n%s = " % name + pprint.pformat(var)
189 for (name, struct) in structs:
190 str = str + "\n%s =\n" % name + pprint.pformat(struct, 4)
191 return str
192 #end def __str__
194 def parseSummary(self): abstract
195 """should fill the class variables with the parsed information"""
197 def getSummaryText(self):
198 return self.summaryText
200 def insertOrUpdate(self):
201 # First : check all needed info is filled in the object, especially for the initial select
203 # Notes on DB Insert
204 # Some identified issues for tourneys already in the DB (which occurs when the HH file is parsed and inserted before the Summary)
205 # Be careful on updates that could make the HH import not match the tourney inserted from a previous summary import !!
206 # BuyIn/Fee can be at 0/0 => match may not be easy
207 # Only one existinf Tourney entry for Matrix Tourneys, but multiple Summary files
208 # Starttime may not match the one in the Summary file : HH = time of the first Hand / could be slighltly different from the one in the summary file
209 # Note: If the TourneyNo could be a unique id .... this would really be a relief to deal with matrix matches ==> Ask on the IRC / Ask Fulltilt ??
211 self.playerIds = self.db.getSqlPlayerIDs(self.players, self.siteId)
212 #for player in self.players:
213 # id=self.db.get_player_id(self.config, self.siteName, player)
214 # if not id:
215 # id=self.db.insertPlayer(unicode(player), self.siteId)
216 # self.playerIds.update({player:id})
218 #print "TS.insert players",self.players,"playerIds",self.playerIds
220 self.buyinCurrency=self.currency
221 self.dbid_pids=self.playerIds #TODO:rename this field in Hand so this silly renaming can be removed
223 #print "TS.self before starting insert",self
224 self.tourneyTypeId = self.db.getSqlTourneyTypeIDs(self)
225 self.tourneyId = self.db.createOrUpdateTourney(self)
226 self.tourneysPlayersIds = self.db.createOrUpdateTourneysPlayers(self)
227 self.db.commit()
229 logging.debug(_("Tourney Insert/Update done"))
231 # TO DO : Return what has been done (tourney created, updated, nothing)
232 # ?? stored = 1 if tourney is fully created / duplicates = 1, if everything was already here and correct / partial=1 if some things were already here (between tourney, tourneysPlayers and handsPlayers)
233 # if so, prototypes may need changes to know what has been done or make some kind of dict in Tourney object that could be updated during the insert process to store that information
234 stored = 0
235 duplicates = 0
236 partial = 0
237 errors = 0
238 ttime = 0
239 return (stored, duplicates, partial, errors, ttime)
242 def addPlayer(self, rank, name, winnings, winningsCurrency, rebuyCount, addOnCount, koCount):
243 """\
244 Adds a player to the tourney, and initialises data structures indexed by player.
245 rank (int) indicating the finishing rank (can be -1 if unknown)
246 name (string) player name
247 winnings (int) the money the player ended the tourney with (can be 0, or -1 if unknown)
249 log.debug(_("addPlayer: rank:%s - name : '%s' - Winnings (%s)") % (rank, name, winnings))
250 self.players.append(name)
251 if rank:
252 self.ranks.update( { name : rank } )
253 self.winnings.update( { name : winnings } )
254 self.winningsCurrency.update( { name : winningsCurrency } )
255 else:
256 self.ranks.update( { name : None } )
257 self.winnings.update( { name : None } )
258 self.winningsCurrency.update( { name : None } )
259 if rebuyCount:
260 self.rebuyCounts.update( {name: Decimal(rebuyCount) } )
261 else:
262 self.rebuyCounts.update( {name: None } )
264 if addOnCount:
265 self.addOnCounts.update( {name: Decimal(addOnCount) } )
266 else:
267 self.addOnCounts.update( {name: None } )
269 if koCount:
270 self.koCounts.update( {name : Decimal(koCount) } )
271 else:
272 self.koCounts.update( {name: None } )
273 #end def addPlayer
275 def incrementPlayerWinnings(self, name, additionnalWinnings):
276 log.debug(_("incrementPlayerWinnings: name : '%s' - Add Winnings (%s)") % (name, additionnalWinnings))
277 oldWins = 0
278 if self.winnings.has_key(name):
279 oldWins = self.winnings[name]
280 else:
281 self.players.append([-1, name, 0])
283 self.winnings[name] = oldWins + Decimal(additionnalWinnings)
285 def checkPlayerExists(self,player):
286 if player not in [p[1] for p in self.players]:
287 print "checkPlayerExists", player, "fail"
288 raise FpdbParseError
290 def updateSessionsCache(self, sc, gsc, tz, doinsert):
291 self.heros = self.db.getHeroIds(self.dbid_pids, self.siteName)
292 sc = self.db.prepSessionsCache(self.tourNo, self.dbid_pids, self.startTime, sc , self.heros, doinsert)
294 gsc = self.db.storeSessionsCache(self.tourNo, self.dbid_pids, self.startTime, {'type': 'summary'}
295 ,None, self.assembleInfo(), sc, gsc, tz, self.heros, doinsert)
296 return sc, gsc
298 def assembleInfo(self):
299 info = {}
300 info['tourneyTypeId'] = self.tourneyTypeId
301 info['winnings'] = self.winnings
302 info['winningsCurrency'] = self.winningsCurrency
303 info['buyinCurrency'] = self.buyinCurrency
304 info['buyin'] = self.buyin
305 info['fee'] = self.fee
306 return info
308 def writeSummary(self, fh=sys.__stdout__):
309 print >>fh, "Override me"
311 def printSummary(self):
312 self.writeSummary(sys.stdout)