summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--playoff.js137
-rw-r--r--playoff.py205
-rw-r--r--playoff/__init__.py0
-rw-r--r--playoff/sql.py23
-rw-r--r--playoff/template.py116
6 files changed, 483 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a8b70d7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.pyc
+*.json
diff --git a/playoff.js b/playoff.js
new file mode 100644
index 0000000..9060c6d
--- /dev/null
+++ b/playoff.js
@@ -0,0 +1,137 @@
+var playoff = {
+
+ settings: {
+ 'winner_h_offset': 10,
+ 'loser_h_offset': 20,
+ 'winner_v_offset': -4,
+ 'loser_v_offset': 4,
+ 'loser_colour': '#ff0000',
+ 'winner_colour': '#00ff00'
+ },
+
+ drawLine: function(ctx, line) {
+ ctx.beginPath();
+ ctx.moveTo(line[0], line[1]);
+ ctx.lineTo(line[2], line[3]);
+ ctx.stroke();
+ },
+
+ run: function() {
+ var boxes = document.getElementsByClassName('playoff_matchbox');
+ var lines = {
+ 'winner': {},
+ 'loser': {}
+ };
+ var boxes_idx = {};
+ for (var b = 0; b < boxes.length; b++) {
+ var id = boxes[b].getAttribute('data-id');
+ boxes_idx[id] = boxes[b];
+ for (var attr in lines) {
+ var value = boxes[b].getAttribute('data-' + attr);
+ if (value) {
+ if (!lines[attr][value]) {
+ lines[attr][value] = [];
+ }
+ lines[attr][value].push(id);
+ }
+ }
+ }
+ var canvas = document.getElementById('playoff_canvas');
+ var ctx = canvas.getContext('2d');
+ for (var type in lines) {
+ ctx.strokeStyle = this.settings[type + '_colour'];
+ for (var from in lines[type]) {
+ var to = lines[type][from];
+ from = from.split(' ');
+ var horizontal_from = [];
+ var vertical_from = [0, canvas.height, 0, 0];
+ for (var f = 0; f < from.length; f++) {
+ var box = boxes_idx[from[f]];
+ var line = [
+ parseInt(box.style.left) + parseInt(box.clientWidth),
+ parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + this.settings[type + '_v_offset'],
+ parseInt(box.style.left) + parseInt(box.clientWidth) + this.settings[type + '_h_offset'],
+ parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + this.settings[type + '_v_offset']
+ ];
+ horizontal_from.push(line);
+ for (var l in horizontal_from) {
+ if (horizontal_from[l][2] < line[2]) {
+ horizontal_from[l][2] = line[2];
+ }
+ if (vertical_from[0] < horizontal_from[l][2]) {
+ vertical_from[0] = horizontal_from[l][2];
+ vertical_from[2] = horizontal_from[l][2];
+ }
+ if (vertical_from[1] > horizontal_from[l][3]) {
+ vertical_from[1] = horizontal_from[l][3];
+ }
+ if (vertical_from[3] < horizontal_from[l][3]) {
+ vertical_from[3] = horizontal_from[l][3];
+ }
+ }
+ }
+ var horizontal_to = [];
+ var vertical_to = [canvas.width, canvas.height, canvas.width, 0];
+ for (var t = 0; t < to.length; t++) {
+ var box = boxes_idx[to[t]];
+ var line = [
+ parseInt(box.style.left),
+ parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + this.settings[type + '_v_offset'],
+ parseInt(box.style.left) - this.settings[type + '_h_offset'],
+ parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + this.settings[type + '_v_offset']
+ ];
+ horizontal_to.push(line);
+ for (var l in horizontal_to) {
+ if (horizontal_to[l][2] > line[2]) {
+ horizontal_to[l][2] = line[2];
+ }
+ if (vertical_to[0] > horizontal_to[l][2]) {
+ vertical_to[0] = horizontal_to[l][2];
+ vertical_to[2] = horizontal_to[l][2];
+ }
+ if (vertical_to[1] > horizontal_to[l][3]) {
+ vertical_to[1] = horizontal_to[l][3];
+ }
+ if (vertical_to[3] < horizontal_to[l][3]) {
+ vertical_to[3] = horizontal_to[l][3];
+ }
+ }
+ }
+ var midpoints = [
+ [
+ (vertical_from[0] + vertical_from[2]) / 2,
+ (vertical_from[1] + vertical_from[3]) / 2
+ ],
+ [
+ (vertical_from[0] + vertical_from[2] + vertical_to[0] + vertical_to[2]) / 4,
+ (vertical_from[1] + vertical_from[3]) / 2
+ ],
+ [
+ (vertical_from[0] + vertical_from[2] + vertical_to[0] + vertical_to[2]) / 4,
+ (vertical_to[1] + vertical_to[3]) / 2
+ ],
+ [
+ (vertical_to[0] + vertical_to[2]) / 2,
+ (vertical_to[1] + vertical_to[3]) / 2
+ ]
+ ]
+ for (var l in horizontal_from) {
+ this.drawLine(ctx, horizontal_from[l]);
+ }
+ this.drawLine(ctx, vertical_from);
+ for (var l in horizontal_to) {
+ this.drawLine(ctx, horizontal_to[l]);
+ }
+ this.drawLine(ctx, vertical_to);
+ for (var m = 0; m < midpoints.length-1; m++) {
+ this.drawLine(ctx, [
+ midpoints[m][0], midpoints[m][1], midpoints[m+1][0], midpoints[m+1][1]
+ ]);
+ }
+ }
+ }
+ }
+
+}
+
+playoff.run();
diff --git a/playoff.py b/playoff.py
new file mode 100644
index 0000000..e2243d8
--- /dev/null
+++ b/playoff.py
@@ -0,0 +1,205 @@
+import json, os, shutil, sys
+import mysql.connector
+from datetime import datetime
+from playoff import sql as p_sql
+from playoff import template as p_temp
+
+settings = json.load(open(sys.argv[1]))
+teams = settings['teams']
+leaderboard = [None] * len(teams)
+
+database = mysql.connector.connect(
+ user=settings['database']['user'],
+ password=settings['database']['pass'],
+ host=settings['database']['host'],
+ port=settings['database']['port']
+)
+db_cursor = database.cursor(buffered=True)
+
+def db_fetch(db, sql, params):
+ db_cursor.execute(sql.replace('#db#', db), params)
+ row = db_cursor.fetchone()
+ return row
+
+def get_shortname(fullname):
+ for team in settings['teams']:
+ if team[0] == fullname:
+ return team[1]
+ return fullname
+
+def get_match_table(match):
+ rows = ''
+ for team in match.teams:
+ rows += p_temp.MATCH_TEAM_ROW % (
+ team.name,
+ ' / '.join([get_shortname(name) for name in team.name.split('<br />')]),
+ team.score
+ )
+ html = p_temp.MATCH_TABLE.decode('utf8') % (
+ int(settings['page']['width'] * 0.75),
+ int(settings['page']['width'] * 0.25),
+ rows
+ )
+ if match.running > 0:
+ html += p_temp.MATCH_RUNNING % (match.link, match.running)
+ return html
+
+def get_match_grid(grid, matches, width, height):
+ grid_boxes = ''
+ col_no = 0
+ for column in grid:
+ grid_x = col_no * (settings['page']['width'] + settings['page']['margin'])
+ grid_header = p_temp.MATCH_GRID_PHASE_RUNNING if len([match for match in column if matches[match].running > 0]) > 0 else p_temp.MATCH_GRID_PHASE
+ grid_boxes += grid_header % (
+ settings['phases'][col_no]['link'],
+ settings['page']['width'],
+ grid_x,
+ settings['phases'][col_no]['title']
+ )
+ row_no = 0
+ column_height = height / len(column)
+ for match in column:
+ grid_y = int(row_no * column_height + 0.5 * (column_height - settings['page']['height']))
+ grid_boxes += p_temp.MATCH_BOX % (
+ grid_x, grid_y,
+ match,
+ ' '.join([str(m) for m in matches[match].winner_matches]) if matches[match].winner_matches is not None else '',
+ ' '.join([str(m) for m in matches[match].loser_matches]) if matches[match].loser_matches is not None else '',
+ get_match_table(matches[match])
+ )
+ row_no += 1
+ col_no += 1
+ return p_temp.MATCH_GRID % (width, height, width, height, grid_boxes)
+
+def get_leaderboard_table(leaderboard):
+ position = 1
+ rows = ''
+ for team in [team if team is not None else '' for team in leaderboard]:
+ rows += p_temp.LEADERBOARD_ROW % (position, team)
+ position +=1
+ html = p_temp.LEADERBOARD.decode('utf8') % (rows)
+ return html
+
+class Team:
+ name = ''
+ score = 0.0
+
+class Match:
+ teams = None
+ running = 0
+ link = '#'
+ winner = None
+ loser = None
+ winner_matches = None
+ loser_matches = None
+
+match_info = {}
+
+def get_match_info(match):
+ info = Match()
+ info.teams = [Team(), Team()]
+ info.winner_matches = []
+ info.loser_matches = []
+ for i in range(0, 2):
+ if 'winner' in match['teams'][i]:
+ info.winner_matches += match['teams'][i]['winner']
+ if 'loser' in match['teams'][i]:
+ info.loser_matches += match['teams'][i]['loser']
+ info.winner_matches = list(set(info.winner_matches))
+ info.loser_matches = list(set(info.loser_matches))
+ try:
+ row = db_fetch(match['database'], p_sql.MATCH_RESULTS, (match['table'], match['round']))
+ info.teams[0].name = row[0]
+ info.teams[1].name = row[1]
+ info.teams[0].score = row[3] + row[5]
+ info.teams[1].score = row[4] + row[6]
+ if row[2] > 0:
+ info.teams[0].score += row[2]
+ else:
+ info.teams[1].score -= row[2]
+ except Exception as e:
+ for i in range(0, 2):
+ if isinstance(match['teams'][i], basestring):
+ info.teams[i].name = match['teams'][i]
+ else:
+ teams = []
+ if 'winner' in match['teams'][i]:
+ teams += [
+ match_info[winner_match].winner
+ for winner_match in match['teams'][i]['winner']
+ ]
+ if 'loser' in match['teams'][i]:
+ teams += [
+ match_info[loser_match].loser
+ for loser_match in match['teams'][i]['loser']
+ ]
+ info.teams[i].name = '<br />'.join([
+ team if team is not None else '??'
+ for team in teams]
+ ) if len([team for team in teams if team is not None]) > 0 else ''
+
+ try:
+ row = db_fetch(match['database'], p_sql.BOARD_COUNT, (match['table'], match['round']))
+ if row[1] > 0:
+ info.running = int(row[1])
+ if row[1] == row[0]:
+ info.running = 0
+ info.winner = info.teams[0].name if info.teams[0].score > info.teams[1].score else info.teams[1].name
+ info.loser = info.teams[1].name if info.teams[0].score > info.teams[1].score else info.teams[0].name
+ except Exception as e:
+ pass
+ return info
+
+grid = []
+for phase in settings['phases']:
+ grid.append([])
+ for match in phase['matches']:
+ match_info[match['id']] = get_match_info(match)
+ match_info[match['id']].link = phase['link']
+ grid[-1].append(match['id'])
+
+leaderboard_teams = {}
+for phase in settings['phases']:
+ for match in phase['matches']:
+ if 'winner' in match:
+ winner_key = tuple(match['winner'])
+ if winner_key not in leaderboard_teams:
+ leaderboard_teams[winner_key] = []
+ leaderboard_teams[winner_key].append(match_info[match['id']].winner)
+ if 'loser' in match:
+ loser_key = tuple(match['loser'])
+ if loser_key not in leaderboard_teams:
+ leaderboard_teams[loser_key] = []
+ leaderboard_teams[loser_key].append(match_info[match['id']].loser)
+
+for positions, teams in leaderboard_teams.iteritems():
+ positions = list(positions)
+ if len(positions) == len([team for team in teams if team is not None]):
+ for table_team in settings['teams']:
+ if table_team[0] in teams:
+ position = positions.pop(0)
+ leaderboard[position-1] = table_team[0]
+
+grid_columns = len(settings['phases'])
+grid_rows = max([len(phase['matches']) for phase in settings['phases']])
+grid_height = grid_rows * (settings['page']['height'] + settings['page']['margin']) - settings['page']['margin']
+grid_width = grid_columns * (settings['page']['width'] + settings['page']['margin']) - settings['page']['margin']
+
+output = open(settings['output'], 'w')
+output.write((
+ p_temp.PAGE % (
+ p_temp.PAGE_HEAD % (
+ p_temp.PAGE_HEAD_REFRESH % (settings['page']['refresh']) if settings['page']['refresh'] > 0 else '',
+ settings['page']['title']
+ ),
+ p_temp.PAGE_BODY % (
+ settings['page']['logoh'],
+ get_match_grid(grid, match_info, grid_width, grid_height),
+ get_leaderboard_table(leaderboard),
+ p_temp.PAGE_BODY_FOOTER.decode('utf8') % (datetime.now().strftime('%Y-%m-%d o %H:%M'))
+ )
+ )).encode('utf8')
+)
+
+shutil.copy(unicode(os.path.join(os.path.dirname(__file__), 'playoff.js')),
+ unicode(os.path.join(os.path.dirname(settings['output']), 'sklady/playoff.js')))
diff --git a/playoff/__init__.py b/playoff/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/playoff/__init__.py
diff --git a/playoff/sql.py b/playoff/sql.py
new file mode 100644
index 0000000..0bd2df7
--- /dev/null
+++ b/playoff/sql.py
@@ -0,0 +1,23 @@
+MATCH_RESULTS = '''
+SELECT t1.fullname, t2.fullname, matches.carry, matches.vph, matches.vpv, matches.corrh, matches.corrv
+FROM #db#.matches matches
+JOIN #db#.teams t1
+ ON t1.id = #db#.matches.homet
+JOIN #db#.teams t2
+ ON t2.id = #db#.matches.visit
+WHERE matches.tabl = %s AND matches.rnd = %s
+'''
+
+BOARD_COUNT = '''
+SELECT segmentsperround*boardspersegment, SUM(sc1.contract IS NOT NULL AND sc2.contract IS NOT NULL)
+FROM #db#.scores sc1
+JOIN #db#.scores sc2
+ ON sc1.rnd = sc2.rnd
+ AND sc1.segment = sc2.segment
+ AND sc1.tabl = sc2.tabl
+ AND sc1.board = sc2.board
+ AND sc1.room = 1
+ AND sc2.room = 2
+JOIN #db#.admin
+WHERE sc1.tabl = %s AND sc1.rnd = %s
+'''
diff --git a/playoff/template.py b/playoff/template.py
new file mode 100644
index 0000000..5fe855c
--- /dev/null
+++ b/playoff/template.py
@@ -0,0 +1,116 @@
+#encoding=utf-8
+
+MATCH_TABLE = '''
+<table border="0" cellspacing="0">
+<tr>
+<td class="s12" width="%d">&nbsp;</td>
+<td class="bdcc2" width="%d">&nbsp;wynik&nbsp;</td>
+</tr>
+%s
+</table>
+'''
+
+MATCH_TEAM_ROW = '''
+<tr>
+<td class="bd1">&nbsp;<a onmouseover="Tip('%s')" onmouseout="UnTip()">%s</a>&nbsp;</td>
+<td class="bdc">&nbsp;%.1f&nbsp;</td>
+</tr>
+'''
+
+MATCH_RUNNING = '''
+<a href="%s" target="_top">
+<img src="images/A.gif" />
+%d
+<img src="images/A.gif" />
+</a>
+'''
+
+MATCH_GRID = '''
+<div style="position: relative; width: %dpx; height: %dpx; margin: 10px">
+<canvas width="%d" height="%d" id="playoff_canvas"></canvas>
+%s
+<script src="sklady/playoff.js" type="text/javascript"></script>
+</div>
+'''
+
+MATCH_GRID_PHASE = '''
+<a href="%s" target="_top" style="display: inline-block; width: %dpx; text-align: center; position: absolute; top: 0; left: %dpx">%s</a>
+'''
+
+MATCH_GRID_RUNNING_PHASE = '''
+<a href="%s" target="_top" style="display: inline-block; width: %dpx; text-align: center; position: absolute; top: 0; left: %dpx">
+<img src="images/A.gif" />
+%s
+<img src="images/A.gif" />
+</a>
+'''
+
+MATCH_BOX = '''
+<div style="position: absolute; left: %dpx; top: %dpx" data-id="%d" data-winner="%s" data-loser="%s" class="playoff_matchbox">
+%s
+</div>
+'''
+
+LEADERBOARD = '''
+<table border="0" cellspacing="0">
+<tr>
+<td class="bdnl12" colspan="2" align="center"><b>KLASYFIKACJA KOŃCOWA</b></td>
+</tr>
+<tr>
+<td class="e" colspan="2">&nbsp;</td>
+</tr>
+<tr>
+<td class="bdcc12">&nbsp;miejsce&nbsp;</td>
+<td class="bdcc2">&nbsp;drużyna&nbsp;</td>
+</tr>
+%s
+</table>
+'''
+
+LEADERBOARD_ROW = '''
+<tr>
+<td class="bdc1">%d</td>
+<td class="bd">&nbsp;%s&nbsp;</td>
+</tr>
+'''
+
+PAGE_HEAD = '''
+<meta http-equiv="Pragma" content="no-cache" />
+<meta http-equiv="Cache-Control" content="no-cache" />
+<meta name="robots" content="noarchive" />
+<meta http-equiv="expires" content="0" />
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="Generator" content="PlayOff" />
+%s
+<title>%s</title>
+<link rel="stylesheet" type="text/css" href="css/kolorki.css" />
+<script type="text/javascript" src="sklady/myAjax.js"></script>
+'''
+
+PAGE_HEAD_REFRESH = '''
+<meta http-equiv="Refresh" content="%d" />
+'''
+
+PAGE_BODY = '''
+<script type="text/javascript" src="sklady/wz_tooltip.js"></script>
+%s
+%s
+%s
+%s
+'''
+
+PAGE_BODY_FOOTER = '''
+<p class="f">&nbsp;Admin&nbsp;&copy;Jan Romański&#39;2005, PlayOff&nbsp;&copyMichał Klichowicz&#39;2017, strona wygenerowana %s</p>
+'''
+
+PAGE = '''
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+%s
+</head>
+<body class="all">
+%s
+</body>
+</html>
+'''