Use debian 2.7 only
[fpbd-bostik.git] / pyfpdb / TourneySummary.py
blob2538af0e3b12817c5739fb52eb3b8d5e5fd33e1a
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, 'Boss':4, 'OnGame':5,
53 'UltimateBet':6, 'Betfair':7, 'Absolute':8, 'PartyPoker':9, 'PacificPoker':10,
54 'Partouche':11, 'Merge':12, 'PKR':13, 'iPoker':14, 'Winamax':15,
55 'Everest':16, 'Cake':17, 'Entraction':18, 'BetOnline':19, 'Microgaming':20 }
58 def __init__(self, db, config, siteName, summaryText, in_path = '-', builtFrom = "HHC"):
59 self.db = db
60 self.config = config
61 self.siteName = siteName
62 self.siteId = self.SITEIDS[siteName]
63 self.in_path = in_path
65 self.summaryText = summaryText
66 self.tourneyName = None
67 self.tourneyTypeId = None
68 self.tourneyId = None
69 self.startTime = None
70 self.endTime = None
71 self.tourNo = None
72 self.currency = None
73 self.buyinCurrency = None
74 self.buyin = 0
75 self.fee = 0
76 self.hero = None
77 self.maxseats = 0
78 self.entries = 0
79 self.speed = "Normal"
80 self.prizepool = 0 # Make it a dict in order to deal (eventually later) with non-money winnings : {'MONEY' : amount, 'OTHER' : Value ??}
81 self.buyInChips = 0
82 self.mixed = None
83 self.isRebuy = False
84 self.isAddOn = False
85 self.isKO = False
86 self.isMatrix = False
87 self.isShootout = False
88 self.matrixMatchId = None # For Matrix tourneys : 1-4 => match tables (traditionnal), 0 => Positional winnings info
89 self.matrixIdProcessed = None
90 self.subTourneyBuyin = None
91 self.subTourneyFee = None
92 self.rebuyChips = None
93 self.addOnChips = None
94 self.rebuyCost = 0
95 self.addOnCost = 0
96 self.totalRebuyCount = None
97 self.totalAddOnCount = None
98 self.koBounty = 0
99 self.tourneyComment = None
100 self.players = []
101 self.isSng = False
102 self.isSatellite = False
103 self.isDoubleOrNothing = False
104 self.guarantee = None
105 self.added = None
106 self.addedCurrency = None
107 self.gametype = {'category':None, 'limitType':None}
108 self.comment = None
109 self.commentTs = None
111 # Collections indexed by player names
112 self.playerIds = {}
113 self.tourneysPlayersIds = {}
114 self.ranks = {}
115 self.winnings = {}
116 self.winningsCurrency = {}
117 self.rebuyCounts = {}
118 self.addOnCounts = {}
119 self.koCounts = {}
121 # currency symbol for this summary
122 self.sym = None
124 if builtFrom=="IMAP":
125 # Fix line endings?
126 pass
127 if self.db == None:
128 self.db = Database.Database(config)
130 self.parseSummary()
131 #end def __init__
133 def __str__(self):
134 #TODO : Update
135 vars = ( (_("SITE"), self.siteName),
136 (_("START TIME"), self.startTime),
137 (_("END TIME"), self.endTime),
138 (_("TOURNEY NAME"), self.tourneyName),
139 (_("TOURNEY NO"), self.tourNo),
140 (_("TOURNEY TYPE ID"), self.tourneyTypeId),
141 (_("TOURNEY ID"), self.tourneyId),
142 (_("BUYIN"), self.buyin),
143 (_("FEE"), self.fee),
144 (_("CURRENCY"), self.currency),
145 (_("HERO"), self.hero),
146 (_("MAX SEATS"), self.maxseats),
147 (_("ENTRIES"), self.entries),
148 (_("SPEED"), self.speed),
149 (_("PRIZE POOL"), self.prizepool),
150 (_("STARTING CHIP COUNT"), self.buyInChips),
151 (_("MIXED"), self.mixed),
152 (_("REBUY"), self.isRebuy),
153 (_("ADDON"), self.isAddOn),
154 (_("KO"), self.isKO),
155 (_("MATRIX"), self.isMatrix),
156 (_("MATRIX ID PROCESSED"), self.matrixIdProcessed),
157 (_("SHOOTOUT"), self.isShootout),
158 (_("MATRIX MATCH ID"), self.matrixMatchId),
159 (_("SUB TOURNEY BUY IN"), self.subTourneyBuyin),
160 (_("SUB TOURNEY FEE"), self.subTourneyFee),
161 (_("REBUY CHIPS"), self.rebuyChips),
162 (_("ADDON CHIPS"), self.addOnChips),
163 (_("REBUY COST"), self.rebuyCost),
164 (_("ADDON COST"), self.addOnCost),
165 (_("TOTAL REBUYS"), self.totalRebuyCount),
166 (_("TOTAL ADDONS"), self.totalAddOnCount),
167 (_("KO BOUNTY"), self.koBounty),
168 (_("TOURNEY COMMENT"), self.tourneyComment),
169 (_("SNG"), self.isSng),
170 (_("SATELLITE"), self.isSatellite),
171 (_("DOUBLE OR NOTHING"), self.isDoubleOrNothing),
172 (_("GUARANTEE"), self.guarantee),
173 (_("ADDED"), self.added),
174 (_("ADDED CURRENCY"), self.addedCurrency),
175 (_("COMMENT"), self.comment),
176 (_("COMMENT TIMESTAMP"), self.commentTs)
179 structs = ( (_("PLAYER IDS"), self.playerIds),
180 (_("PLAYERS"), self.players),
181 (_("TOURNEYS PLAYERS IDS"), self.tourneysPlayersIds),
182 (_("RANKS"), self.ranks),
183 (_("WINNINGS"), self.winnings),
184 (_("WINNINGS CURRENCY"), self.winningsCurrency),
185 (_("COUNT REBUYS"), self.rebuyCounts),
186 (_("COUNT ADDONS"), self.addOnCounts),
187 (_("COUNT KO"), self.koCounts)
189 str = ''
190 for (name, var) in vars:
191 str = str + "\n%s = " % name + pprint.pformat(var)
193 for (name, struct) in structs:
194 str = str + "\n%s =\n" % name + pprint.pformat(struct, 4)
195 return str
196 #end def __str__
198 def getSplitRe(self, head): abstract
199 """Function to return a re object to split the summary text into separate tourneys, based on head of file"""
201 def parseSummary(self): abstract
202 """should fill the class variables with the parsed information"""
204 def getSummaryText(self):
205 return self.summaryText
207 @staticmethod
208 def clearMoneyString(money):
209 "Renders 'numbers' like '1 200' and '2,000'"
210 return money.replace(' ', '').replace(',', '')
212 def insertOrUpdate(self, printtest = False):
213 # First : check all needed info is filled in the object, especially for the initial select
215 # Notes on DB Insert
216 # Some identified issues for tourneys already in the DB (which occurs when the HH file is parsed and inserted before the Summary)
217 # Be careful on updates that could make the HH import not match the tourney inserted from a previous summary import !!
218 # BuyIn/Fee can be at 0/0 => match may not be easy
219 # Only one existinf Tourney entry for Matrix Tourneys, but multiple Summary files
220 # 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
221 # 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 ??
222 self.db.set_printdata(printtest)
224 self.playerIds = self.db.getSqlPlayerIDs(self.players, self.siteId)
225 #for player in self.players:
226 # id=self.db.get_player_id(self.config, self.siteName, player)
227 # if not id:
228 # id=self.db.insertPlayer(unicode(player), self.siteId)
229 # self.playerIds.update({player:id})
231 #print "TS.insert players",self.players,"playerIds",self.playerIds
232 self.dbid_pids=self.playerIds #TODO:rename this field in Hand so this silly renaming can be removed
234 #print "TS.self before starting insert",self
235 self.tourneyTypeId = self.db.createOrUpdateTourneyType(self)
236 self.tourneyId = self.db.createOrUpdateTourney(self)
237 self.db.createOrUpdateTourneysPlayers(self)
238 self.db.commit()
240 logging.debug(_("Tourney Insert/Update done"))
242 # TO DO : Return what has been done (tourney created, updated, nothing)
243 # ?? 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)
244 # 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
245 stored = 0
246 duplicates = 0
247 partial = 0
248 errors = 0
249 ttime = 0
250 return (stored, duplicates, partial, errors, ttime)
253 def addPlayer(self, rank, name, winnings, winningsCurrency, rebuyCount, addOnCount, koCount):
254 """\
255 Adds a player to the tourney, and initialises data structures indexed by player.
256 rank (int) indicating the finishing rank (can be -1 if unknown)
257 name (string) player name
258 winnings (int) the money the player ended the tourney with (can be 0, or -1 if unknown)
260 log.debug("addPlayer: rank:%s - name : '%s' - Winnings (%s)" % (rank, name, winnings))
261 if name in self.players:
262 if rank:
263 if rank > self.ranks[name]:
264 self.ranks[name] = rank
265 self.winnings[name] += winnings
266 self.winningsCurrency.update( { name : winningsCurrency } )
267 self.rebuyCounts[name] += 1
268 else:
269 self.players.append(name)
270 if rank:
271 self.ranks.update( { name : rank } )
272 self.winnings.update( { name : winnings } )
273 self.winningsCurrency.update( { name : winningsCurrency } )
274 else:
275 self.ranks.update( { name : None } )
276 self.winnings.update( { name : 0 } )
277 self.winningsCurrency.update( { name : None } )
278 if rebuyCount:
279 self.rebuyCounts.update( {name: rebuyCount } )
280 else:
281 self.rebuyCounts.update( {name: 0 } )
283 if addOnCount:
284 self.addOnCounts.update( {name: addOnCount } )
285 else:
286 self.addOnCounts.update( {name: 0 } )
288 if koCount:
289 self.koCounts.update( {name : koCount } )
290 else:
291 self.koCounts.update( {name: 0 } )
292 #end def addPlayer
294 def incrementPlayerWinnings(self, name, additionnalWinnings):
295 log.debug("incrementPlayerWinnings: name : '%s' - Add Winnings (%s)" % (name, additionnalWinnings))
296 oldWins = 0
297 if self.winnings.has_key(name):
298 oldWins = self.winnings[name]
299 else:
300 self.players.append([-1, name, 0])
302 self.winnings[name] = oldWins + Decimal(additionnalWinnings)
304 def checkPlayerExists(self,player):
305 if player not in [p[1] for p in self.players]:
306 log.error(_("TourneySummary: Tried to add info for unknown player: '%s'") % player)
307 raise FpdbParseError
309 def writeSummary(self, fh=sys.__stdout__):
310 print >>fh, "Override me"
312 def printSummary(self):
313 self.writeSummary(sys.stdout)