chiark / gitweb /
364f08888f0e1cdf4e1050b36bc298f70ad660dd
[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\
67                                 , text = name)
68                 else:
69                         return row[0] + "," +str(row[1])
70
71 def print_age_count(row,newLine):
72         if newLine == '<br>':
73                 script = "age.py?age="+str(row[0])
74                 link = link_Template.substitute(script = \
75                         script, text = row[0])
76                 return str(row[1]) + ' people had children at age '\
77                          + link + newLine
78         else:
79                 return print_row(row,newLine)
80
81
82 def print_name_count(row,newLine):
83         if newLine=='<br>':
84                 script = "name.py?name=" + row[0]
85                 link = link_Template.substitute(script =\
86                         script, text = row[0])
87                 return str(row[1]) + " people called "+link + newLine
88         else:
89                 return print_row(row,newLine)   
90
91 def print_tagged_name(relationship,row,newLine):
92         if row[0]==None:
93                 out = relationship + " not yet entered: " + row[1]
94         else:
95                 if newLine == '<br>':
96                         html = 1
97                 else:
98                         html=0
99                 if relationship =='':
100                         out = name_html(row,html) + '   '
101                 else:
102                         out = relationship + ": " + name_html(row,html)
103         return out + newLine
104
105 def month_numbers(monthN):
106         if monthN == 0:
107                 month ='unknown month'
108         elif monthN == 1:
109                 month ='January'
110         elif monthN==2:
111                 month ='February'
112         elif monthN==3:
113                 month ='March'
114         elif monthN==4:
115                 month ='April'
116         elif monthN==5:
117                 month ='May'
118         elif monthN==6:
119                 month ='June'
120         elif monthN==7:
121                 month ='July'
122         elif monthN==8:
123                 month ='August'
124         elif monthN==9:
125                 month ='September'
126         elif monthN==10:
127                 month ='October'
128         elif monthN==11:
129                 month ='November'
130         elif monthN==12:
131                 month ='December'
132         else:
133                 month = 'Incorrectly entered month ' + str(monthN)
134         return month
135
136 def ordinal_numbers(number):
137         number = int(number)
138         if number % 10==1 and number/10 % 10 !=1:
139                 out = str(number) +'st'
140         elif number % 10==2 and number/10 % 10 !=1:
141                 out = str(number) +'nd'
142         elif number % 10==3 and number/10 % 10 !=1:
143                 out = str(number) +'rd'
144         else:
145                 out = str(number) +'th'
146         return out
147
148 def list_territories(newLine):
149         s = "SELECT DISTINCT territory"\
150         +" FROM territories"\
151         +" ORDER BY territory;"
152
153         out = ''
154         for row in run_query(s,()):
155                 out =out + terr_html(row[0],newLine) +newLine
156         return out
157
158
159 def list_people(newLine):
160         s = "SELECT name,id,bornyear"\
161         +" FROM people"\
162         +" ORDER BY bornyear;"
163
164         out = ''
165         year = 0
166         out = out + 'born in unknown year:' +newLine
167         for row in run_query(s,()):
168                 if row[2]!=0 and row[2]/100==0:
169                         out = out +newLine+ 'born in 1st century:' +newLine
170
171                 if row[2]/100!=year/100:
172                         century = row[2]/100 + 1
173                         out = out +newLine+ 'born in ' 
174
175                         out = out +ordinal_numbers(century) \
176                                 + ' century:' + newLine
177
178                 out = out + name_html(row,newLine) +newLine
179
180                 if row[2] == 0: #unknown year
181
182                         t = (row[1],) #person ID
183
184
185                         #died
186                         u = "SELECT diedyear FROM people WHERE ID = ?;"
187
188                         bornAfter = 0
189                         for r in run_query(u,t):
190                                 if r[0] !=0:
191                                         out = out + "died: "\
192                                          + str(r[0]) + newLine
193                                         bornAfter = r[0] -100
194
195                         #find children
196                         u = "Select people.bornYear from"\
197                                 +" people INNER JOIN parents"\
198                                 +" ON people.ID = parents.ID"\
199                                 +" WHERE parents.parentID = ?"\
200                                 + " ORDER BY people.bornYear;"
201                         
202                         hadChild=[]
203                         
204                         for r in run_query(u,t):
205                                 if r[0] != 0:
206                                         hadChild.append(r[0])
207                         
208                         bornBefore = 0
209                         if len(hadChild)!=0:
210                                 out = out + "had children in: "
211                                 for c in hadChild:
212                                         out = out + str(c) + ','
213                                 out = out[:-1] + newLine
214
215                                 bornBefore = hadChild[0]-12
216                                 if bornAfter==0:
217                                         bornAfter = hadChild[0]-100
218                         
219                         if bornAfter!=0:
220                                 if bornBefore == 0: 
221                                         out = out + "probably born "\
222                                                 +"after " + str(bornAfter)
223                                 else:
224                                         out = out + "probably born "\
225                                                 +"betwen " + str(bornAfter)\
226                                                 +" and " + str(bornBefore)
227                                 out = out + newLine
228
229
230                 year = row[2]
231         return out
232
233 def count_names(newLine):
234         s = "SELECT firstName, count(*)"\
235         +" FROM people"\
236         +" GROUP BY firstName"\
237         +" ORDER BY count(*) DESC;"
238
239         out = ''
240         for row in run_query(s,()):
241                 out = out + print_name_count(row,newLine)
242
243         return out
244
245 def people_with_name(name,newLine):
246         s = "SELECT Name, ID"\
247         +" FROM people"\
248         +" WHERE Name LIKE ?;"
249
250         out = ''
251
252         t = (name + '%',)
253
254         for row in run_query(s,t):
255                 out = out + name_html(row,newLine) + newLine
256
257         return out
258
259 def count_birth_month(newLine):
260         s = "SELECT bornMonth, count(*)"\
261                 +" FROM people"\
262                 +" GROUP BY bornMonth"\
263                 +" ORDER BY bornMonth;"
264
265         t = "SELECT * FROM people WHERE bornMonth = ?;"
266
267         out = ''
268         for row in run_query(s,()):
269                 month = month_numbers(row[0])
270                 out = out + month + ': ' + str(row[1]) + newLine
271
272                 if row[0]>12:
273                         u = (row[0],)
274                         out =  out +print_query(t,u,newLine)
275                 
276         return out
277
278 def count_death_month(newLine):
279         s = "SELECT diedMonth, count(*)"\
280                 +" FROM people"\
281                 +" GROUP BY diedMonth"\
282                 +" ORDER BY diedMonth;"
283
284         t = "SELECT * FROM people WHERE diedMonth = ?;"
285
286         out = ''
287         for row in run_query(s,()):
288                 month = month_numbers(row[0])
289                 out = out + month + ': ' + str(row[1]) + newLine
290
291                 if row[0]>12:
292                         u = (row[0],)
293                         out =  out +print_query(t,u,newLine)
294
295         return out
296
297 def count_age_at_child(newLine):
298
299         s = "select p1.bornYear - p2.bornYear as age, count(*)"\
300                 +" FROM"\
301                 +" parents INNER JOIN people p1"\
302                 +" ON parents.ID = p1.ID"\
303                 +" INNER JOIN people p2"\
304                 +" ON parents.parentID = p2.ID"\
305                 +" WHERE p1.bornYear <> 0 and p2.bornYear<>0"\
306                 +" GROUP BY age;"
307
308         out = ''
309         for row in run_query(s,()):
310                 out = out + print_age_count(row,newLine)
311
312         return out
313
314 def people_had_child_at_age(age,newLine):
315
316         s = "select p1.bornYear - p2.bornYear as age, p1.name, p1.ID"\
317                 +",p2.name,p2.ID FROM"\
318                 +" parents INNER JOIN people p1"\
319                 +" ON parents.ID = p1.ID"\
320                 +" INNER JOIN people p2"\
321                 +" ON parents.parentID = p2.ID"\
322                 +" WHERE age = ? AND p1.bornYear<>0 AND p2.bornYear<>0"
323
324         t = (int(age),)
325
326         out = ''
327         out = 'At age ' + str(age) + ' :'
328         for row in run_query(s,t):
329                 out = out + newLine
330                 out =out + name_html([row[3],row[4]],newLine) + ' had '\
331                         +name_html([row[1],row[2]],newLine)
332
333         return out
334
335
336 def all_ancestors(personID,newLine):
337         #find parents
338         s = "SELECT people.Name,parents.parentID FROM"\
339                 +" parents LEFT JOIN people"\
340                 +" ON parents.parentID = people.ID"\
341                 +" WHERE parents.ID = ?"\
342                 +" AND parents.parentID <> '.';"
343
344
345         ancestors = [personID]
346         allAncestors = [personID]
347         trackLevel = [0]
348         level = 0
349
350         t = "SELECT name,id FROM people WHERE id==?"
351         id = (personID,)
352
353         out = "Ancestors of "
354         for row in run_query(t,id):
355                 out = out + name_html(row,newLine)+newLine
356
357         while len(ancestors)>0:
358                 level = level+1
359                 newA =[]
360                 thisout = newLine + parent_level(level,'parent') +':' + newLine
361                 for ancestor in ancestors:
362                         id = (ancestor,)
363                         for row in run_query(s,id):
364                                 thisout = thisout + name_html(row,newLine)+newLine
365                                 if row[1] not in allAncestors and is_number(row[1])!=0:
366                                         newA.append(row[1])
367                                         allAncestors.append(row[1])
368                                         trackLevel.append(level)
369                 ancestors = newA
370                 if len(ancestors)>0:
371                         out  = out+thisout
372         
373
374         return [out, allAncestors,trackLevel]
375
376
377 def common_ancestors(IDA, IDB,newLine):
378         out = 'Common ancestors of:' + newLine
379
380         s = "SELECT name,id FROM people WHERE id==?"
381
382
383         names=[]
384         for id in (IDA,IDB):
385                 t = (id,)
386                 for row in run_query(s,t):
387                         out = out + name_html(row,newLine)+newLine
388                         names.append(row[0])
389                 if id==IDA:
390                         out = out + 'and'
391                 out = out + newLine
392
393         if len(names)!=2:
394                 related = 'No details held on one party'
395                 out = out + related
396                 return [out,[],related]
397         
398
399         a = all_ancestors(IDA,newLine)
400         b = all_ancestors(IDB,newLine)
401         
402         ancestorsB = set(b[1])
403         ancestorsA = set(a[1])
404
405         common = ancestorsA.intersection(ancestorsB)
406         common = list(common)
407
408
409         aLevels=[]
410         bLevels=[]
411         for c in common:
412                 i = a[1].index(c)
413                 aLevels.append(a[2][i])
414                 i = b[1].index(c)
415                 bLevels.append(b[2][i])
416
417         s = "SELECT Name, ID, bornyear"\
418         +" FROM people"\
419         +" WHERE ID IN ("
420         for i in range(len(common)):
421                 s = s+ "?,"
422         if len(common)>0:
423                 s = s[:-1]
424
425
426         s = s+") ORDER BY bornyear;"
427
428
429         if len(common)==0:
430                 related = names[0]+' and '+names[1]+' are not related'
431                 out = out + newLine + related
432                 return [out, common,related]
433
434
435         out = out + print_tagged_query('',s,common,newLine)
436
437         indexA=[]
438         indexB=[]
439
440         for i in range(len(common)):
441                 if aLevels[i] == min(aLevels):
442                         indexA.append(i)
443                 if bLevels[i] == min(bLevels):
444                         indexB.append(i)
445         
446
447
448         s = "SELECT name, id"\
449         +" FROM people"\
450         +" WHERE id=?"
451
452         out  = out + newLine + 'Most Recent Common Ancestors:' + newLine
453         for a in indexA:
454                 t = (common[a],)
455                 out = out + print_tagged_query('',s,t,newLine)
456                 if a!=indexA[-1]:
457                         out = out + 'and' + newLine
458
459         out = out + parent_level(aLevels[indexA[0]],'parent')
460         if len(indexA) >1:
461                 out = out + 's'
462
463         out = out + ' of ' + name_html([names[0],IDA],newLine)+newLine
464
465         out = out + newLine
466         for b in indexB:
467                 t = (common[b],)
468                 out = out + print_tagged_query('',s,t,newLine)
469                 if b!=indexB[-1]:
470                         out = out + 'and' + newLine
471
472         out = out + parent_level(bLevels[indexB[0]],'parent')
473         if len(indexB)>1:
474                 out = out + 's'
475         out = out + ' of ' + name_html([names[1],IDB],newLine)+newLine
476
477
478         al = aLevels[indexA[0]]
479         bl = bLevels[indexB[0]]
480
481         related = relationship(al,bl,names)
482         out = out+newLine + related
483
484         return [out,common,related]
485
486 def relationship(level1, level2,names):
487
488         if level1==0 and level2==0:
489                 return names[0] + ' is ' +names[1]
490         if level1==0:
491                 return names[0] + ' is ' + names[1] + '\'s '+ parent_level(level2,'parent')
492         if level2==0:
493                 return names[1] + ' is ' + names[0] + '\'s '+ parent_level(level1,'parent')
494
495
496         if level1>=level2:
497                 remove = level1-level2
498                 cousinNum = level2-1
499         else:
500                 remove = level2-level1
501                 cousinNum = level1-1
502
503         if cousinNum==0:
504                 uaLevel =  parent_level(remove,'uncle or aunt')
505                 if level1<= level2:
506                         return names[0] + ' is ' + names[1] + '\'s ' + uaLevel
507
508                 if level2<level1:
509                         return names[1] + ' is ' + names[0] + '\'s ' + uaLevel
510
511         c=ordinal_numbers(cousinNum)
512         if remove == 1:
513                 rem = 'once'
514         elif remove ==2:
515                 rem = 'twice'
516         else:
517                 rem = str(remove) + ' times'            
518
519         r = names[0] +' and '+names[1] +' are ' + c + ' cousins '
520         if remove !=0:
521                 r = r+ rem + ' removed'
522
523         return r
524
525 def parent_level(level,type):
526         if level == 0:
527                 if type=='parent':
528                         return 'self'
529                 else:           
530                         return 'sibling'
531         out = type
532         if level ==1:
533                 return out
534         if type =='parent':
535                 out = 'grand '+out
536         else:
537                 out = 'great '+out
538         if level ==2:
539                 return out
540         for i in range(2,level):
541                 out = 'great '+out
542         return out
543
544 def rulers_of(aTerritory,newLine):
545
546         tq = "SELECT name, people.ID, startyear,stopyear,territory"\
547                 +" FROM territories INNER JOIN people"\
548                 +" ON people.ID = territories.ID"\
549                 +" WHERE territory LIKE ?"\
550                 +" ORDER BY territory,startyear,stopyear;"
551
552
553
554         thisT  = ''
555         last = ''
556         out = ''
557         for row in run_query(tq,(aTerritory+'%',)):
558                 if row[4]!=last and last!='':
559                         out  = out + 'Rulers of '+terr_html(last,newLine) +':'+ newLine +thisT +newLine
560                         thisT = ''
561
562                 thisT = thisT +name_html(row,newLine)
563                 thisT = thisT +' from ' + str(row[2])+' to '+str(row[3]) + newLine
564                 last = row[4]
565
566         out  = out + 'Rulers of '+terr_html(row[4],newLine) +':'+ newLine +thisT
567
568         return out      
569
570 def person_info(personID,newLine):
571         t = (personID,)
572
573         output = '';
574         
575         #Id, Name, Dates, Style, Style-Dates
576         s = "SELECT * FROM people WHERE ID = ?"
577         for row in run_query(s,t):
578                 output = output + 'ID: '+str(row[0]) +newLine
579                 output = output + print_tagged_name('Name',[row[1], row[0]],newLine) +newLine
580                 output = output + 'Born: '+row[3] + newLine
581                 bornYear = row[4]
582                 output = output + 'Died: '+row[5] + newLine
583
584         s = "SELECT * FROM styles WHERE ID = ?"
585         for row in run_query(s,t):
586                 output = output +newLine+ 'Style: '+row[1] + newLine
587
588                 output = output + 'Territories:' + newLine
589
590                 u = "SELECT * FROM territories"\
591                 +"  WHERE ID =? AND startYear =? AND stopYear=?"
592                 v=(personID,row[3],row[5])
593
594                 any = 0
595                 for r in run_query(u,v):
596                         output = output + terr_html(r[1],newLine) +','
597                         any = 1
598                 if any ==1:
599                         output = output[:-1] + newLine
600
601                 output = output +  'From: '+row[2] + newLine
602                 output = output +  'To: '+row[4] + newLine
603
604         s = "SELECT people.Name,consort "\
605                 +"FROM consorts LEFT JOIN people"\
606                 +" ON people.ID = consorts.consort"\
607                 +" WHERE consorts.ID = ?"
608         for row in run_query(s,t):
609                 output = output + print_tagged_name('Consort',row,newLine)
610
611         output = output + newLine
612         #find parents
613         s = "SELECT people.Name,parents.parentID FROM"\
614                 +" parents LEFT JOIN people"\
615                 +" ON parents.parentID = people.ID"\
616                 +" WHERE parents.ID = ?"
617         for row in run_query(s,t):
618                 output = output + print_tagged_name('Parent',row,newLine)
619
620         #find spouses
621         s = "SELECT people.NAME, marriages.IDb from"\
622                 +" marriages LEFT JOIN people"\
623                 +" ON people.ID = marriages.IDb"\
624                 +" WHERE marriages.IDa = ?"
625         for row in run_query(s,t):
626                 output = output + newLine
627                 output = output + print_tagged_name('Spouse',row,newLine)
628                 output = output + relationship_html(personID,row[1],newLine)
629
630         s = "SELECT people.NAME, marriages.IDa from"\
631                 +" marriages LEFT JOIN people"\
632                 +" ON people.ID = marriages.IDa"\
633                 +" WHERE marriages.IDb = ?"
634         for row in run_query(s,t):    
635                 output = output + newLine
636                 output = output + print_tagged_name('Spouse',row,newLine)
637                 output = output + relationship_html(personID,row[1],newLine)
638
639         output = output + newLine
640
641         #find children
642         s = "Select people.NAME, people.ID ,people.bornYear"\
643                 +" FROM people INNER JOIN parents"\
644                 +" ON people.ID = parents.ID"\
645                 +" WHERE parents.parentID = ?"\
646                 +" ORDER BY people.bornYear;"
647
648         for row in run_query(s,t):
649                 output = output  + print_tagged_name('Child',row,newLine)
650
651                  #find children's other parent
652                 u = "Select people.NAME, parents.parentID FROM"\
653                 +" parents LEFT JOIN people"\
654                 +" ON people.ID = parents.parentID"\
655                 +" WHERE parents.ID = ? AND parents.parentID <> ?"
656
657                 ids = (row[1],t[0])
658
659                 for r in run_query(u,ids):
660                         output = output + print_tagged_name('With',r,newLine)
661
662                 #age when child born
663                 age = row[2]-bornYear
664                 output = output[:-4] + " at the age of "+str(age) + newLine
665
666         output = output + newLine
667
668         return output
669
670 def connect():
671         global conn
672         conn = sqlite3.connect('/home/naath/familyTreeProject/familyTree/tree.db')
673         return conn
674
675 def make_cursor():
676         return conn.cursor()
677         
678 def close(conn):
679         conn.close
680
681 #def main():
682
683 #       [c, conn] = connect()   
684 #
685 #       person_info(1,c)
686 #       person_info(17,c)
687 #       person_info(38,c)
688 #       person_info(90,c)
689 #
690 #       close(conn)