chiark / gitweb /
Much fiddling including - consorts, birth month and death month lists
[familyTree.git] / familyTree / askQuestion.py
1 #!/usr/bin/python
2
3 import sqlite3
4 import findYear
5 from string import Template
6
7 global link_Template 
8 link_Template= Template("<a href = http://www.chiark.greenend.org.uk/ucgi/~naath/$script>$text</a>")
9
10 def run_query(s,t):
11         c = make_cursor()
12         return c.execute(s,t)
13
14 def print_row(row,newLine):
15         out = ''
16         for item in row:
17                 out = out + str(item)+'|'
18         return out[:-1] + newLine
19
20 def print_query(s,t,newLine):
21         printMe = ''
22         for row in run_query(s,t):
23                 printMe = printMe + print_row(row,newLine)              
24         return printMe
25
26 def is_number(s):
27     try:
28         float(s)
29         return 1
30     except ValueError:
31         return 0
32
33 def print_tagged_query(relationship,s,t,newLine):
34         mine = ''
35         for row in run_query(s,t):
36                 mine = mine + print_tagged_name(relationship,row,newLine)
37         return mine
38
39
40 def relationship_html(ID,ID2,newLine):
41         if newLine=='<br>':
42                 relationship = common_ancestors(ID,ID2,newLine)[2]
43                 script = "ancestors.py?ID="+str(ID)+"&ID2="+str(ID2)
44                 url = link_Template.substitute(script = script,text = "Common ancestors")
45                 return relationship + ' '+url + newLine
46         else:
47                 return ''
48
49 def terr_html(terr,newLine):
50         if newLine=='<br>':
51                 return link_Template.substitute(script = "territory.py?terr="+terr, text=terr)
52         else:
53                 return terr
54 def name_html(row,html):
55         if html=='<br>':
56                 html=1
57         elif html=='\n':
58                 html=0
59
60         if row[0] == None:
61                 return row[1]
62         else:
63                 if html==1:
64                         script = "person.py?ID=" + str(row[1])
65                         name = row[0]
66                         return link_Template.substitute(script = script, text = name)
67                 else:
68                         return row[0] + "," +str(row[1])
69
70 def print_tagged_name(relationship,row,newLine):
71         if row[0]==None:
72                 out = relationship + " not yet entered: " + row[1]
73         else:
74                 if newLine == '<br>':
75                         html = 1
76                 else:
77                         html=0
78                 if relationship =='':
79                         out = name_html(row,html) + '   '
80                 else:
81                         out = relationship + ": " + name_html(row,html)
82         return out + newLine
83
84 def month_numbers(monthN):
85         if monthN == 0:
86                 month ='unknown month'
87         elif monthN == 1:
88                 month ='January'
89         elif monthN==2:
90                 month ='February'
91         elif monthN==3:
92                 month ='March'
93         elif monthN==4:
94                 month ='April'
95         elif monthN==5:
96                 month ='May'
97         elif monthN==6:
98                 month ='June'
99         elif monthN==7:
100                 month ='July'
101         elif monthN==8:
102                 month ='August'
103         elif monthN==9:
104                 month ='September'
105         elif monthN==10:
106                 month ='October'
107         elif monthN==11:
108                 month ='November'
109         elif monthN==12:
110                 month ='December'
111         else:
112                 month = 'Incorrectly entered month ' + str(monthN)
113         return month
114
115 def ordinal_numbers(number):
116         number = int(number)
117         if number % 10==1 and number/10 % 10 !=1:
118                 out = str(number) +'st'
119         elif number % 10==2 and number/10 % 10 !=1:
120                 out = str(number) +'nd'
121         elif number % 10==3 and number/10 % 10 !=1:
122                 out = str(number) +'rd'
123         else:
124                 out = str(number) +'th'
125         return out
126
127 def list_territories(newLine):
128         s = "SELECT DISTINCT territory"\
129         +" FROM territories"\
130         +" ORDER BY territory;"
131
132         out = ''
133         for row in run_query(s,()):
134                 out =out + terr_html(row[0],newLine) +newLine
135         return out
136
137 def list_people(newLine):
138         s = "SELECT name,id,bornyear"\
139         +" FROM people"\
140         +" ORDER BY bornyear;"
141
142         out = ''
143         year = 0
144         out = out + 'born in unknown year:' +newLine
145         for row in run_query(s,()):
146                 if row[2]!=0 and row[2]/100==0:
147                         out = out +newLine+ 'born in 1st century:' +newLine
148
149                 if row[2]/100!=year/100:
150                         century = row[2]/100 + 1
151                         out = out +newLine+ 'born in ' 
152
153                         out = out +ordinal_numbers(century) + ' century:' + newLine
154
155                 out = out + name_html(row,newLine) +newLine
156                 year = row[2]
157         return out
158
159 def count_names(newLine):
160         s = "SELECT firstName, count(*)"\
161         +" FROM people"\
162         +" GROUP BY firstName"\
163         +" ORDER BY count(*) DESC;"
164
165         out = print_query(s,(),newLine)
166         
167
168         return out
169
170 def count_birth_month(newLine):
171         s = "SELECT bornMonth, count(*)"\
172                 +" FROM people"\
173                 +" GROUP BY bornMonth"\
174                 +" ORDER BY bornMonth;"
175
176         t = "SELECT * FROM people WHERE bornMonth = ?;"
177
178         out = ''
179         for row in run_query(s,()):
180                 month = month_numbers(row[0])
181                 out = out + month + ': ' + str(row[1]) + newLine
182
183                 if row[0]>12:
184                         u = (row[0],)
185                         out =  out +print_query(t,u,newLine)
186                 
187         return out
188
189 def count_death_month(newLine):
190         s = "SELECT diedMonth, count(*)"\
191                 +" FROM people"\
192                 +" GROUP BY diedMonth"\
193                 +" ORDER BY diedMonth;"
194
195         t = "SELECT * FROM people WHERE diedMonth = ?;"
196
197         out = ''
198         for row in run_query(s,()):
199                 month = month_numbers(row[0])
200                 out = out + month + ': ' + str(row[1]) + newLine
201
202                 if row[0]>12:
203                         u = (row[0],)
204                         out =  out +print_query(t,u,newLine)
205
206         return out
207
208
209 def all_ancestors(personID,newLine):
210         #find parents
211         s = "SELECT people.Name,parents.parentID FROM"\
212                 +" parents LEFT JOIN people"\
213                 +" ON parents.parentID = people.ID"\
214                 +" WHERE parents.ID = ?"\
215                 +" AND parents.parentID <> '.';"
216
217
218         ancestors = [personID]
219         allAncestors = [personID]
220         trackLevel = [0]
221         level = 0
222
223         t = "SELECT name,id FROM people WHERE id==?"
224         id = (personID,)
225
226         out = "Ancestors of "
227         for row in run_query(t,id):
228                 out = out + name_html(row,newLine)+newLine
229
230         while len(ancestors)>0:
231                 level = level+1
232                 newA =[]
233                 thisout = newLine + parent_level(level,'parent') +':' + newLine
234                 for ancestor in ancestors:
235                         id = (ancestor,)
236                         for row in run_query(s,id):
237                                 thisout = thisout + name_html(row,newLine)+newLine
238                                 if row[1] not in allAncestors and is_number(row[1])!=0:
239                                         newA.append(row[1])
240                                         allAncestors.append(row[1])
241                                         trackLevel.append(level)
242                 ancestors = newA
243                 if len(ancestors)>0:
244                         out  = out+thisout
245         
246
247         return [out, allAncestors,trackLevel]
248
249
250 def common_ancestors(IDA, IDB,newLine):
251         out = 'Common ancestors of:' + newLine
252
253         s = "SELECT name,id FROM people WHERE id==?"
254
255
256         names=[]
257         for id in (IDA,IDB):
258                 t = (id,)
259                 for row in run_query(s,t):
260                         out = out + name_html(row,newLine)+newLine
261                         names.append(row[0])
262                 if id==IDA:
263                         out = out + 'and'
264                 out = out + newLine
265
266         if len(names)!=2:
267                 related = 'No details held on one party'
268                 out = out + related
269                 return [out,[],related]
270         
271
272         a = all_ancestors(IDA,newLine)
273         b = all_ancestors(IDB,newLine)
274         
275         ancestorsB = set(b[1])
276         ancestorsA = set(a[1])
277
278         common = ancestorsA.intersection(ancestorsB)
279         common = list(common)
280
281
282         aLevels=[]
283         bLevels=[]
284         for c in common:
285                 i = a[1].index(c)
286                 aLevels.append(a[2][i])
287                 i = b[1].index(c)
288                 bLevels.append(b[2][i])
289
290         s = "SELECT Name, ID, bornyear"\
291         +" FROM people"\
292         +" WHERE ID IN ("
293         for i in range(len(common)):
294                 s = s+ "?,"
295         if len(common)>0:
296                 s = s[:-1]
297
298
299         s = s+") ORDER BY bornyear;"
300
301
302         if len(common)==0:
303                 related = names[0]+' and '+names[1]+' are not related'
304                 out = out + newLine + related
305                 return [out, common,related]
306
307
308         out = out + print_tagged_query('',s,common,newLine)
309
310         indexA=[]
311         indexB=[]
312
313         for i in range(len(common)):
314                 if aLevels[i] == min(aLevels):
315                         indexA.append(i)
316                 if bLevels[i] == min(bLevels):
317                         indexB.append(i)
318         
319
320
321         s = "SELECT name, id"\
322         +" FROM people"\
323         +" WHERE id=?"
324
325         out  = out + newLine + 'Most Recent Common Ancestors:' + newLine
326         for a in indexA:
327                 t = (common[a],)
328                 out = out + print_tagged_query('',s,t,newLine)
329                 if a!=indexA[-1]:
330                         out = out + 'and' + newLine
331
332         out = out + parent_level(aLevels[indexA[0]],'parent')
333         if len(indexA) >1:
334                 out = out + 's'
335
336         out = out + ' of ' + name_html([names[0],IDA],newLine)+newLine
337
338         out = out + newLine
339         for b in indexB:
340                 t = (common[b],)
341                 out = out + print_tagged_query('',s,t,newLine)
342                 if b!=indexB[-1]:
343                         out = out + 'and' + newLine
344
345         out = out + parent_level(bLevels[indexB[0]],'parent')
346         if len(indexB)>1:
347                 out = out + 's'
348         out = out + ' of ' + name_html([names[1],IDB],newLine)+newLine
349
350
351         al = aLevels[indexA[0]]
352         bl = bLevels[indexB[0]]
353
354         related = relationship(al,bl,names)
355         out = out+newLine + related
356
357         return [out,common,related]
358
359 def relationship(level1, level2,names):
360
361         if level1==0 and level2==0:
362                 return names[0] + ' is ' +names[1]
363         if level1==0:
364                 return names[0] + ' is ' + names[1] + '\'s '+ parent_level(level2,'parent')
365         if level2==0:
366                 return names[1] + ' is ' + names[0] + '\'s '+ parent_level(level1,'parent')
367
368
369         if level1>=level2:
370                 remove = level1-level2
371                 cousinNum = level2-1
372         else:
373                 remove = level2-level1
374                 cousinNum = level1-1
375
376         if cousinNum==0:
377                 uaLevel =  parent_level(remove,'uncle or aunt')
378                 if level1<= level2:
379                         return names[0] + ' is ' + names[1] + '\'s ' + uaLevel
380
381                 if level2<level1:
382                         return names[1] + ' is ' + names[0] + '\'s ' + uaLevel
383
384         c=ordinal_numbers(cousinNum)
385         if remove == 1:
386                 rem = 'once'
387         elif remove ==2:
388                 rem = 'twice'
389         else:
390                 rem = str(remove) + ' times'            
391
392         r = names[0] +' and '+names[1] +' are ' + c + ' cousins '
393         if remove !=0:
394                 r = r+ rem + ' removed'
395
396         return r
397
398 def parent_level(level,type):
399         if level == 0:
400                 if type=='parent':
401                         return 'self'
402                 else:           
403                         return 'sibling'
404         out = type
405         if level ==1:
406                 return out
407         if type =='parent':
408                 out = 'grand '+out
409         else:
410                 out = 'great '+out
411         if level ==2:
412                 return out
413         for i in range(2,level):
414                 out = 'great '+out
415         return out
416
417 def rulers_of(aTerritory,newLine):
418
419         tq = "SELECT name, people.ID, startyear,stopyear,territory"\
420                 +" FROM territories INNER JOIN people"\
421                 +" ON people.ID = territories.ID"\
422                 +" WHERE territory LIKE ?"\
423                 +" ORDER BY territory,startyear,stopyear;"
424
425
426
427         thisT  = ''
428         last = ''
429         out = ''
430         for row in run_query(tq,(aTerritory+'%',)):
431                 if row[4]!=last and last!='':
432                         out  = out + 'Rulers of '+terr_html(last,newLine) +':'+ newLine +thisT +newLine
433                         thisT = ''
434
435                 thisT = thisT +name_html(row,newLine)
436                 thisT = thisT +' from ' + str(row[2])+' to '+str(row[3]) + newLine
437                 last = row[4]
438
439         out  = out + 'Rulers of '+terr_html(row[4],newLine) +':'+ newLine +thisT
440
441         return out      
442
443 def person_info(personID,newLine):
444         t = (personID,)
445
446         output = '';
447         
448         #Id, Name, Dates, Style, Style-Dates
449         s = "SELECT * FROM people WHERE ID = ?"
450         for row in run_query(s,t):
451                 output = output + 'ID: '+str(row[0]) +newLine
452                 output = output + print_tagged_name('Name',[row[1], row[0]],newLine) +newLine
453                 output = output + 'Born: '+row[3] + newLine
454                 output = output + 'Died: '+row[5] + newLine
455
456         s = "SELECT * FROM styles WHERE ID = ?"
457         for row in run_query(s,t):
458                 output = output +newLine+ 'Style: '+row[1] + newLine
459
460                 output = output + 'Territories:' + newLine
461
462                 u = "SELECT * FROM territories"\
463                 +"  WHERE ID =? AND startYear =? AND stopYear=?"
464                 v=(personID,row[3],row[5])
465
466                 any = 0
467                 for r in run_query(u,v):
468                         output = output + terr_html(r[1],newLine) +','
469                         any = 1
470                 if any ==1:
471                         output = output[:-1] + newLine
472
473                 output = output +  'From: '+row[2] + newLine
474                 output = output +  'To: '+row[4] + newLine
475
476         s = "SELECT people.Name,consort "\
477                 +"FROM consorts LEFT JOIN people"\
478                 +" ON people.ID = consorts.consort"\
479                 +" WHERE consorts.ID = ?"
480         for row in run_query(s,t):
481                 output = output + print_tagged_name('Consort',row,newLine)
482
483         output = output + newLine
484         #find parents
485         s = "SELECT people.Name,parents.parentID FROM"\
486                 +" parents LEFT JOIN people"\
487                 +" ON parents.parentID = people.ID"\
488                 +" WHERE parents.ID = ?"
489         for row in run_query(s,t):
490                 output = output + print_tagged_name('Parent',row,newLine)
491
492         #find spouses
493         s = "SELECT people.NAME, marriages.IDb from"\
494                 +" marriages LEFT JOIN people"\
495                 +" ON people.ID = marriages.IDb"\
496                 +" WHERE marriages.IDa = ?"
497         for row in run_query(s,t):
498                 output = output + newLine
499                 output = output + print_tagged_name('Spouse',row,newLine)
500                 output = output + relationship_html(personID,row[1],newLine)
501
502         s = "SELECT people.NAME, marriages.IDa from"\
503                 +" marriages LEFT JOIN people"\
504                 +" ON people.ID = marriages.IDa"\
505                 +" WHERE marriages.IDb = ?"
506         for row in run_query(s,t):    
507                 output = output + newLine
508                 output = output + print_tagged_name('Spouse',row,newLine)
509                 output = output + relationship_html(personID,row[1],newLine)
510
511         output = output + newLine
512
513         #find children
514         s = "Select people.NAME, people.ID from"\
515                 +" people INNER JOIN parents"\
516                 +" ON people.ID = parents.ID"\
517                 +" WHERE parents.parentID = ?"
518
519         for row in run_query(s,t):
520                 output = output  + print_tagged_name('Child',row,newLine)
521
522                  #find children's other parent
523                 u = "Select people.NAME, parents.parentID FROM"\
524                 +" parents LEFT JOIN people"\
525                 +" ON people.ID = parents.parentID"\
526                 +" WHERE parents.ID = ? AND parents.parentID <> ?"
527
528                 ids = (row[1],t[0])
529
530                 for row in run_query(u,ids):
531                         output = output + print_tagged_name('With',row,newLine)
532
533         output = output + newLine
534
535         return output
536
537 def connect():
538         global conn
539         conn = sqlite3.connect('/home/naath/familyTreeProject/familyTree/tree.db')
540         return conn
541
542 def make_cursor():
543         return conn.cursor()
544         
545 def close(conn):
546         conn.close
547
548 #def main():
549
550 #       [c, conn] = connect()   
551 #
552 #       person_info(1,c)
553 #       person_info(17,c)
554 #       person_info(38,c)
555 #       person_info(90,c)
556 #
557 #       close(conn)