chiark / gitweb /
7606ab59441bf4708f943fb3669119dba4e981a9
[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                         u = "Select styles.startYear, styles.style from"\
220                                 +" people INNER JOIN styles"\
221                                 +" ON people.ID = styles.ID"\
222                                 +" WHERE people.ID = ? and"\
223                                 +" styles.startYear <>0"\
224                                 +" ORDER BY styles.startYear;"
225
226                         for r in run_query(u,t):
227                                 out = out + r[1] + " from " + str(r[0])\
228                                 + newLine
229                                 if bornAfter ==0:
230                                         bornAfter = r[0] -100
231                                 break
232
233                         if bornAfter!=0:
234                                 if bornBefore == 0: 
235                                         out = out + "probably born "\
236                                                 +"after " + str(bornAfter)
237                                 else:
238                                         out = out + "probably born "\
239                                                 +"betwen " + str(bornAfter)\
240                                                 +" and " + str(bornBefore)
241                                 out = out + newLine
242
243                 year = row[2]
244         return out
245
246 def count_names(newLine):
247         s = "SELECT firstName, count(*)"\
248         +" FROM people"\
249         +" GROUP BY firstName"\
250         +" ORDER BY count(*) DESC;"
251
252         out = ''
253         for row in run_query(s,()):
254                 out = out + print_name_count(row,newLine)
255
256         return out
257
258 def people_with_name(name,newLine):
259         s = "SELECT Name, ID"\
260         +" FROM people"\
261         +" WHERE Name LIKE ?;"
262
263         out = ''
264
265         t = (name + '%',)
266
267         for row in run_query(s,t):
268                 out = out + name_html(row,newLine) + newLine
269
270         return out
271
272 def count_birth_month(newLine):
273         s = "SELECT bornMonth, count(*)"\
274                 +" FROM people"\
275                 +" GROUP BY bornMonth"\
276                 +" ORDER BY bornMonth;"
277
278         t = "SELECT * FROM people WHERE bornMonth = ?;"
279
280         out = ''
281         for row in run_query(s,()):
282                 month = month_numbers(row[0])
283                 out = out + month + ': ' + str(row[1]) + newLine
284
285                 if row[0]>12:
286                         u = (row[0],)
287                         out =  out +print_query(t,u,newLine)
288                 
289         return out
290
291 def count_death_month(newLine):
292         s = "SELECT diedMonth, count(*)"\
293                 +" FROM people"\
294                 +" GROUP BY diedMonth"\
295                 +" ORDER BY diedMonth;"
296
297         t = "SELECT * FROM people WHERE diedMonth = ?;"
298
299         out = ''
300         for row in run_query(s,()):
301                 month = month_numbers(row[0])
302                 out = out + month + ': ' + str(row[1]) + newLine
303
304                 if row[0]>12:
305                         u = (row[0],)
306                         out =  out +print_query(t,u,newLine)
307
308         return out
309
310 def count_age_at_child(newLine):
311
312         s = "select p1.bornYear - p2.bornYear as age, count(*)"\
313                 +" FROM"\
314                 +" parents INNER JOIN people p1"\
315                 +" ON parents.ID = p1.ID"\
316                 +" INNER JOIN people p2"\
317                 +" ON parents.parentID = p2.ID"\
318                 +" WHERE p1.bornYear <> 0 and p2.bornYear<>0"\
319                 +" GROUP BY age;"
320
321         out = ''
322         for row in run_query(s,()):
323                 out = out + print_age_count(row,newLine)
324
325         return out
326
327 def people_had_child_at_age(age,newLine):
328
329         s = "select p1.bornYear - p2.bornYear as age, p1.name, p1.ID"\
330                 +",p2.name,p2.ID FROM"\
331                 +" parents INNER JOIN people p1"\
332                 +" ON parents.ID = p1.ID"\
333                 +" INNER JOIN people p2"\
334                 +" ON parents.parentID = p2.ID"\
335                 +" WHERE age = ? AND p1.bornYear<>0 AND p2.bornYear<>0"
336
337         t = (int(age),)
338
339         out = ''
340         out = 'At age ' + str(age) + ' :'
341         for row in run_query(s,t):
342                 out = out + newLine
343                 out =out + name_html([row[3],row[4]],newLine) + ' had '\
344                         +name_html([row[1],row[2]],newLine)
345
346         return out
347
348
349 def all_ancestors(personID,newLine):
350         #find parents
351         s = "SELECT people.Name,parents.parentID FROM"\
352                 +" parents LEFT JOIN people"\
353                 +" ON parents.parentID = people.ID"\
354                 +" WHERE parents.ID = ?"\
355                 +" AND parents.parentID <> '.';"
356
357
358         ancestors = [personID]
359         allAncestors = [personID]
360         trackLevel = [0]
361         level = 0
362
363         t = "SELECT name,id FROM people WHERE id==?"
364         id = (personID,)
365
366         out = "Ancestors of "
367         for row in run_query(t,id):
368                 out = out + name_html(row,newLine)+newLine
369
370         while len(ancestors)>0:
371                 level = level+1
372                 newA =[]
373                 thisout = newLine + parent_level(level,'parent') +':' + newLine
374                 for ancestor in ancestors:
375                         id = (ancestor,)
376                         for row in run_query(s,id):
377                                 thisout = thisout + name_html(row,newLine)+newLine
378                                 if row[1] not in allAncestors and is_number(row[1])!=0:
379                                         newA.append(row[1])
380                                         allAncestors.append(row[1])
381                                         trackLevel.append(level)
382                 ancestors = newA
383                 if len(ancestors)>0:
384                         out  = out+thisout
385         
386
387         return [out, allAncestors,trackLevel]
388
389
390 def common_ancestors(IDA, IDB,newLine):
391         out = 'Common ancestors of:' + newLine
392
393         s = "SELECT name,id FROM people WHERE id==?"
394
395
396         names=[]
397         for id in (IDA,IDB):
398                 t = (id,)
399                 for row in run_query(s,t):
400                         out = out + name_html(row,newLine)+newLine
401                         names.append(row[0])
402                 if id==IDA:
403                         out = out + 'and'
404                 out = out + newLine
405
406         if len(names)!=2:
407                 related = 'No details held on one party'
408                 out = out + related
409                 return [out,[],related]
410         
411
412         a = all_ancestors(IDA,newLine)
413         b = all_ancestors(IDB,newLine)
414         
415         ancestorsB = set(b[1])
416         ancestorsA = set(a[1])
417
418         common = ancestorsA.intersection(ancestorsB)
419         common = list(common)
420
421
422         aLevels=[]
423         bLevels=[]
424         for c in common:
425                 i = a[1].index(c)
426                 aLevels.append(a[2][i])
427                 i = b[1].index(c)
428                 bLevels.append(b[2][i])
429
430         s = "SELECT Name, ID, bornyear"\
431         +" FROM people"\
432         +" WHERE ID IN ("
433         for i in range(len(common)):
434                 s = s+ "?,"
435         if len(common)>0:
436                 s = s[:-1]
437
438
439         s = s+") ORDER BY bornyear;"
440
441
442         if len(common)==0:
443                 related = names[0]+' and '+names[1]+' are not related'
444                 out = out + newLine + related
445                 return [out, common,related]
446
447
448         out = out + print_tagged_query('',s,common,newLine)
449
450         indexA=[]
451         indexB=[]
452
453         for i in range(len(common)):
454                 if aLevels[i] == min(aLevels):
455                         indexA.append(i)
456                 if bLevels[i] == min(bLevels):
457                         indexB.append(i)
458         
459
460
461         s = "SELECT name, id"\
462         +" FROM people"\
463         +" WHERE id=?"
464
465         out  = out + newLine + 'Most Recent Common Ancestors:' + newLine
466         for a in indexA:
467                 t = (common[a],)
468                 out = out + print_tagged_query('',s,t,newLine)
469                 if a!=indexA[-1]:
470                         out = out + 'and' + newLine
471
472         out = out + parent_level(aLevels[indexA[0]],'parent')
473         if len(indexA) >1:
474                 out = out + 's'
475
476         out = out + ' of ' + name_html([names[0],IDA],newLine)+newLine
477
478         out = out + newLine
479         for b in indexB:
480                 t = (common[b],)
481                 out = out + print_tagged_query('',s,t,newLine)
482                 if b!=indexB[-1]:
483                         out = out + 'and' + newLine
484
485         out = out + parent_level(bLevels[indexB[0]],'parent')
486         if len(indexB)>1:
487                 out = out + 's'
488         out = out + ' of ' + name_html([names[1],IDB],newLine)+newLine
489
490
491         al = aLevels[indexA[0]]
492         bl = bLevels[indexB[0]]
493
494         related = relationship(al,bl,names)
495         out = out+newLine + related
496
497         return [out,common,related]
498
499 def relationship(level1, level2,names):
500
501         if level1==0 and level2==0:
502                 return names[0] + ' is ' +names[1]
503         if level1==0:
504                 return names[0] + ' is ' + names[1] + '\'s '+ parent_level(level2,'parent')
505         if level2==0:
506                 return names[1] + ' is ' + names[0] + '\'s '+ parent_level(level1,'parent')
507
508
509         if level1>=level2:
510                 remove = level1-level2
511                 cousinNum = level2-1
512         else:
513                 remove = level2-level1
514                 cousinNum = level1-1
515
516         if cousinNum==0:
517                 uaLevel =  parent_level(remove,'uncle or aunt')
518                 if level1<= level2:
519                         return names[0] + ' is ' + names[1] + '\'s ' + uaLevel
520
521                 if level2<level1:
522                         return names[1] + ' is ' + names[0] + '\'s ' + uaLevel
523
524         c=ordinal_numbers(cousinNum)
525         if remove == 1:
526                 rem = 'once'
527         elif remove ==2:
528                 rem = 'twice'
529         else:
530                 rem = str(remove) + ' times'            
531
532         r = names[0] +' and '+names[1] +' are ' + c + ' cousins '
533         if remove !=0:
534                 r = r+ rem + ' removed'
535
536         return r
537
538 def parent_level(level,type):
539         if level == 0:
540                 if type=='parent':
541                         return 'self'
542                 else:           
543                         return 'sibling'
544         out = type
545         if level ==1:
546                 return out
547         if type =='parent':
548                 out = 'grand '+out
549         else:
550                 out = 'great '+out
551         if level ==2:
552                 return out
553         for i in range(2,level):
554                 out = 'great '+out
555         return out
556
557 def rulers_of(aTerritory,newLine):
558
559         tq = "SELECT name, people.ID, startyear,stopyear,territory"\
560                 +" FROM territories INNER JOIN people"\
561                 +" ON people.ID = territories.ID"\
562                 +" WHERE territory LIKE ?"\
563                 +" ORDER BY territory,startyear,stopyear;"
564
565
566
567         thisT  = ''
568         last = ''
569         out = ''
570         for row in run_query(tq,(aTerritory+'%',)):
571                 if row[4]!=last and last!='':
572                         out  = out + 'Rulers of '+terr_html(last,newLine) +':'+ newLine +thisT +newLine
573                         thisT = ''
574
575                 thisT = thisT +name_html(row,newLine)
576                 thisT = thisT +' from ' + str(row[2])+' to '+str(row[3]) + newLine
577                 last = row[4]
578
579         out  = out + 'Rulers of '+terr_html(row[4],newLine) +':'+ newLine +thisT
580
581         return out      
582
583 def person_info(personID,newLine):
584         t = (personID,)
585
586         output = '';
587         
588         #Id, Name, Dates, Style, Style-Dates
589         s = "SELECT * FROM people WHERE ID = ?"
590         for row in run_query(s,t):
591                 output = output + 'ID: '+str(row[0]) +newLine
592                 output = output + print_tagged_name('Name',[row[1], row[0]],newLine) +newLine
593                 output = output + 'Born: '+row[3] + newLine
594                 bornYear = row[4]
595                 output = output + 'Died: '+row[5] + newLine
596
597         s = "SELECT * FROM styles WHERE ID = ?"
598         for row in run_query(s,t):
599                 output = output +newLine+ 'Style: '+row[1] + newLine
600
601                 output = output + 'Territories:' + newLine
602
603                 u = "SELECT * FROM territories"\
604                 +"  WHERE ID =? AND startYear =? AND stopYear=?"
605                 v=(personID,row[3],row[5])
606
607                 any = 0
608                 for r in run_query(u,v):
609                         output = output + terr_html(r[1],newLine) +','
610                         any = 1
611                 if any ==1:
612                         output = output[:-1] + newLine
613
614                 output = output +  'From: '+row[2] + newLine
615                 output = output +  'To: '+row[4] + newLine
616
617         s = "SELECT people.Name,consort "\
618                 +"FROM consorts LEFT JOIN people"\
619                 +" ON people.ID = consorts.consort"\
620                 +" WHERE consorts.ID = ?"
621         for row in run_query(s,t):
622                 output = output + print_tagged_name('Consort',row,newLine)
623
624         output = output + newLine
625         #find parents
626         s = "SELECT people.Name,parents.parentID FROM"\
627                 +" parents LEFT JOIN people"\
628                 +" ON parents.parentID = people.ID"\
629                 +" WHERE parents.ID = ?"
630         for row in run_query(s,t):
631                 output = output + print_tagged_name('Parent',row,newLine)
632
633         #find spouses
634         s = "SELECT people.NAME, marriages.IDb from"\
635                 +" marriages LEFT JOIN people"\
636                 +" ON people.ID = marriages.IDb"\
637                 +" WHERE marriages.IDa = ?"
638         for row in run_query(s,t):
639                 output = output + newLine
640                 output = output + print_tagged_name('Spouse',row,newLine)
641                 output = output + relationship_html(personID,row[1],newLine)
642
643         s = "SELECT people.NAME, marriages.IDa from"\
644                 +" marriages LEFT JOIN people"\
645                 +" ON people.ID = marriages.IDa"\
646                 +" WHERE marriages.IDb = ?"
647         for row in run_query(s,t):    
648                 output = output + newLine
649                 output = output + print_tagged_name('Spouse',row,newLine)
650                 output = output + relationship_html(personID,row[1],newLine)
651
652         output = output + newLine
653
654         #find children
655         s = "Select people.NAME, people.ID ,people.bornYear"\
656                 +" FROM people INNER JOIN parents"\
657                 +" ON people.ID = parents.ID"\
658                 +" WHERE parents.parentID = ?"\
659                 +" ORDER BY people.bornYear;"
660
661         for row in run_query(s,t):
662                 output = output  + print_tagged_name('Child',row,newLine)
663
664                  #find children's other parent
665                 u = "Select people.NAME, parents.parentID FROM"\
666                 +" parents LEFT JOIN people"\
667                 +" ON people.ID = parents.parentID"\
668                 +" WHERE parents.ID = ? AND parents.parentID <> ?"
669
670                 ids = (row[1],t[0])
671
672                 for r in run_query(u,ids):
673                         output = output + print_tagged_name('With',r,newLine)
674
675                 #age when child born
676                 if row[2] !=0 and bornYear != 0:
677                         age = row[2]-bornYear
678                         output = output[:-4] + " at the age of "+str(age) + newLine
679
680         output = output + newLine
681
682         return output
683
684 def connect():
685         global conn
686         conn = sqlite3.connect('/home/naath/familyTreeProject/familyTree/tree.db')
687         return conn
688
689 def make_cursor():
690         return conn.cursor()
691         
692 def close(conn):
693         conn.close
694
695 #def main():
696
697 #       [c, conn] = connect()   
698 #
699 #       person_info(1,c)
700 #       person_info(17,c)
701 #       person_info(38,c)
702 #       person_info(90,c)
703 #
704 #       close(conn)