# Keith Briggs 2017-07-15 - include code for Roman numerals to reduce dependencies
# contains some ideas taken from http://people.albion.edu/imacinnes/calendar/Regnal_Years.html

import re
from sys import exit,path

numeral_map=(
  (1000,'M'),
  ( 900,'CM'),
  ( 500,'D'),
  ( 400,'CD'),
  ( 100,'C'),
  (  90,'XC'),
  (  50,'L'),
  (  40,'XL'),
  (  10,'X'),
  (   9,'IX'),
  (   5,'V'),
  (   4,'IV'),
  (   1,'I'),
)

def int_to_roman(i):
  result=[]
  for integer, numeral in numeral_map:
    count=int(i/integer)
    result.append(numeral*count)
    i-=integer*count
  x=''.join(result)
  return x

def roman_to_int(nn):
  n=nn.upper()
  i=result=0
  for integer, numeral in numeral_map:
    while n[i:i+len(numeral)]==numeral:
      result+=integer
      i+=len(numeral)
  return result

monarchs={
  'William':   re.compile(r'(?P<y>\d+)\s*(?P<k>W|Wi|Wm|Will|William)\s*(?P<n>II?|[12])$'),
  'Henry':     re.compile(r'(?P<y>\d+)\s*(?P<k>H|Hen|Hy|Henry)\s*(?P<n>(I|II|III|IV|V|VI|VII|VIII)|[12345678])$'),
  'Stephen':   re.compile(r'(?P<y>\d+)\s*(?P<k>S|St|Steph|Stephen)$'),
  'John':      re.compile(r'(?P<y>\d+)\s*(?P<k>J|Jo|John)$'),
  'Mary':      re.compile(r'(?P<y>\d+)\s*(?P<k>M|My|Mary)$'),
  'Elizabeth': re.compile(r'(?P<y>\d+)\s*(?P<k>El|Eliz|Elizabeth)$'),
  'Richard':   re.compile(r'(?P<y>\d+)\s*(?P<k>R|Rich|Richard|Rch)\s*(?P<n>(I|II|III)|[123])$'),
  'Edward':    re.compile(r'(?P<y>\d+)\s*(?P<k>E|Ed|Edw|Edward)\s*(?P<n>(I|II|III|IV|V|VI|VII|VIII)|[12345678])$'),
  'Charles':   re.compile(r'(?P<y>\d+)\s*(?P<k>C|Ch|Charles)\s*(?P<n>(I|II)|[12])$'),
  'George':    re.compile(r'(?P<y>\d+)\s*(?P<k>G|Geo|George)\s*(?P<n>(I|II|III|IV|V|VI)|[123456])$'),
}

def parse_regnal_year_spec(spec):
  for monarch in monarchs:
    m=monarchs[monarch].match(spec)
    if m:
      n=m.group('n')
      try:
        n=int(n)
      except:
        n=roman_to_int(n)
      return int(m.group('y')),monarch,n
  return None

def check_re_William():
  for x in ('1 W 1','1Will I','3 Will II','3 Will 2','3 Hy 4','3Wm2'):
    m=re_William.match(x)
    if m:
      print('"%s":'%x,parse_regnal_year_spec(x))
    else:
      print('"%s":'%x,'no match')

def check_re_Henry():
  for x in ('1 H 1','1Hen I','31 Henry II','3 Hen 2','3 Hy V','3Wm2'):
    m=re_Henry.match(x)
    if m:
      print('"%s":'%x,parse_regnal_year_spec(x))
    else:
      print('"%s":'%x,'no match')

def alert(msg):
  return # !!!
  print(msg)

def get_regnalyear(regnalyear,monarch,month=0,day=0):

  if monarch in ('William 1','WilliamI','William i','William I','Wi I','Wi 1','Wi1','W1','W 1'):
    if regnalyear>21:
      alert('William I only reigned for 21 years')
      regnalyear='error'
    regnalyear+=1065
    if month==12 and day<25: regnalyear+=1
    if month<12: regnalyear+=1
    return str(regnalyear)

  if monarch in ('William 2','WilliamII','William ii','William II','Wi II','Wi 2','Wi2','W2','W 2'):
    if regnalyear>13:
      alert('William II only reigned for 13 years')
      regnalyear='error'
    regnalyear+=1086
    if month==9 and day<26: regnalyear+=1
    if month<9: regnalyear+=1

  elif monarch in ('HenryI','Henry I','Henry i','Henry 1','Henry1','Henry 1','Henry1'):
    if regnalyear>36: 
      alert('Henry I only reigned for 36 years')
      regnalyear='error'
    regnalyear+=1099
    if month==8 and day<5: regnalyear+=1
    if month<8: regnalyear+=1

  elif monarch=='Stephen':
    if regnalyear>19:
      alert('Stephen only reigned for 19 years')
      regnalyear='error'
    regnalyear+=1134
    if month==12 and day<22: regnalyear+=1
    if month<12: regnalyear+=1

  elif monarch in ('HenryII','Henry II','Henry ii','Henry 2','Henry2','Henry 2','Hen2','Hy2','Hy 2','H2'):
    if regnalyear>35:
      alert('Henry II only reigned for 35 years')
      regnalyear='error'
    regnalyear+=1153
    if month==12 and day<19: regnalyear+=1
    if month<12: regnalyear+=1

  elif monarch in ('RichardI','Richard i','Richard 1'):
    if regnalyear>10:
      alert('Richard I only reigned for 10 years')
      regnalyear='error'
    regnalyear+=1188
    if month==9 and day<3: regnalyear+=1
    if month<9: regnalyear+=1

  elif monarch in ('HenryIII','Henry III','Henry iii','Henry 3','Henry3','Henry 3','Hen3','Hy3','Hy 3','H3'):
    if regnalyear>57:
      alert('Henry III only reigned for 57 years')
      regnalyear='error'
    regnalyear+=1215
    if month==10 and day<28: regnalyear+=1
    if month<10: regnalyear+=1

  elif monarch in ('Edward 1','Edward1','EdwardI','Edward I','Edward i','Edward1','Edward 1','Ed 1','Ed1'):
    if regnalyear>35:
      alert('Edward I only reigned for 35 years')
      regnalyear='error'
    #print(regnalyear,monarch)
    regnalyear+=1271
    if month==11 and day<20: regnalyear+=1
    if month<11: regnalyear+=1

  elif monarch in ('Edward 2','Edward2','EdwardII','Edward II','Edward ii','Edward2','Edward 2','Ed 2','Ed2'):
    if regnalyear>20:
      alert('Edward II only reigned for 20 years')
      regnalyear='error'
    regnalyear+=1306
    if month==7 and day<8: regnalyear+=1
    if month<7: regnalyear+=1

  elif monarch in ('Edward 3','Edward3','EdwardIII','Edward III','Edward III','Edward iii','Edward3','Edward 3','Ed 3','Ed3'):
    if regnalyear>51:
      alert('Edward III only reigned for 51 years')
      regnalyear='error'
    regnalyear+=1326
    if month==1 and day<25: regnalyear+=1

  elif monarch in ('RichardII','Richard ii','Richard 2'):
    if regnalyear>23:
      alert('Richard II only reigned for 23 years')
      regnalyear='error'
    regnalyear+=1376
    if month==6 and day<22: regnalyear+=1
    if month<6: regnalyear+=1

  elif monarch in ('Henry 4','HenryIV','Henry IV','Henry iv','Henry 4','Henry4','Henry 4','Hen4','Hy4','Hy 4','H4',):
    if regnalyear>14:
      alert('Henry IV only reigned for 14 years')
      regnalyear='error'
    regnalyear+=1398
    if month==9 and day<30: regnalyear+=1
    if month<9: regnalyear+=1

  elif monarch in ('HenryV','Henry V','Henry v','Henry 5','Henry5','Henry 5','Hen5','Hy5','Hy 5','H5'):
    if regnalyear>10:
      alert('Henry V only reigned for 10 years')
      regnalyear='error'
    regnalyear+=1412
    if month==3 and day<21: regnalyear+=1
    if month<3: regnalyear+=1

  elif monarch in ('HenryVI','Henry VI','Henry vi','Henry 6','Henry6','Henry 6','Hen6','Hy6','Hy 6','H6'):
    if regnalyear>39:
      alert('Henry VI only reigned for 39 years')
      regnalyear='error'
    regnalyear+=1421
    if month==8: regnalyear+=1
    if month<8:  regnalyear+=1

  elif monarch in ('EdwardIV','Edward IV','Edward iv','Edward4','Edward 4','Ed 4','Ed4'):
    if regnalyear>23:
      alert('Edward IV only reigned for 23 years')
      regnalyear='error'
    regnalyear+=1460
    if month==3 and day<4: regnalyear+=1
    if month<3: regnalyear+=1

  elif monarch in ('EdwardV','Edward V','Edward v','Edward5','Edward 5','Ed 5','Ed5'):
    if regnalyear>1:
      alert('Edward V only reigned for 1 year')
      regnalyear='error'
    regnalyear+=1482
    if month==4 and day<9:
      alert("Edward V's reign lasted from 9 April to 25 June")
      regnalyear='error'
    if month<4: 
      alert("Edward V's reign lasted from 9 April to 25 June")
      regnalyear='error'
    if month==6 and day>25:
      alert("Edward V's reign lasted from 9 April to 25 June")
      regnalyear='error'
    if month>6:
      alert("Edward V's reign lasted from 9 April to 25 June")
      regnalyear='error'

  elif monarch in ('RichardIII','Richard iii','Richard 3'):
    if regnalyear>3:
      alert('Richard III only reigned for 3 years')
      regnalyear='error'
    regnalyear+=1482
    if month==6 and day<26: regnalyear+=1
    if month<6: regnalyear+=1

  #if monarch=='Richard iv': return 0 # Keith Briggs 2014-08-29 !!

  elif monarch in ('HenryVII','Henry VII','Henry vii','Henry 7','Henry7','Henry 7','Hen7','Hy7','Hy 7','H7'):
    if regnalyear>24:
      alert('Henry VII only reigned for 24 years')
      regnalyear='error'
    regnalyear+=1484
    if month==8 and day<22: regnalyear+=1
    if month<8: regnalyear+=1

  elif monarch in ('HenryVIII','Henry VIII','Henry viii','Henry 8','Henry8','Henry 8','Hen8','Hy8','Hy 8','H8'):
    if regnalyear>38:
      alert('Henry VIII only reigned for 38 years')
      regnalyear='error'
    regnalyear+=1508
    if month==4 and day<22: regnalyear+=1
    if month<4: regnalyear+=1

  elif monarch=='EdwardVI':
    if regnalyear>7:
      alert('EdwardVI only reigned for 7 years')
      regnalyear='error'
    regnalyear+=1546
    if month==1 and day<28: regnalyear+=1

  elif monarch=='Elizabeth':
    if regnalyear>45:
      alert('Elizabeth I only reigned for 45 years')
      regnalyear='error'
    regnalyear+=1557
    if month==11 and day<17: regnalyear+=1
    if month<11: regnalyear+=1

  elif monarch=='JamesI':
    if regnalyear>23:
      alert('James I had only 23 regnal years as King of England')
      regnalyear='error'
    regnalyear+=1602
    if month==3 and day<24: regnalyear+=1
    if month<3: regnalyear+=1

  elif monarch=='CharlesI':
    if regnalyear>24:
      alert('Charles I only reigned for 24 years')
      regnalyear='error'
    regnalyear+=1624
    if month==3 and day<27: regnalyear+=1
    if month<3: regnalyear+=1

  elif monarch=='CharlesII':
    if regnalyear>37:
      alert('Charles II only had 37 regnal years')
      regnalyear='error'
    regnalyear+=1648
    if month==1 and day<30: regnalyear+=1

  elif monarch=='JamesII':
    if regnalyear>4:
      alert('James II only reigned for 4 years')
      regnalyear='error'
    regnalyear+=1684
    if month==2 and day<6: regnalyear+=1
    if month==1: regnalyear+=1
  
  elif monarch=='Mary':
    if regnalyear>6:
      alert('Mary only reigned for 4 years')
      regnalyear='error'
    alert("This site calculates the regnal years for Mary, ignoring Philip and his regnal years. The calculation of regnal years between July 9, 1553 and November 17, 1558 is complicated by Mary's marriage to Philip.")
    regnalyear+=1552
    if month==7 and day<6: regnalyear+=1
    if month<7: regnalyear+=1

  elif monarch=='WilliamandMary':
    if regnalyear>14:
      alert('William only reigned for 14 years (the first six with Mary)')
      return
    regnalyear+=1688
    if month==2 and day<13: regnalyear+=1
    if month==1: regnalyear+=1
  elif monarch=='Anne':
    if regnalyear>13:
      alert('Anne only reigned for 13 years.')
      return
    regnalyear+=1701
    if month==3 and day<8: regnalyear+=1
    if month<3: regnalyear+=1

  elif monarch=='GeorgeI':
    if regnalyear>13:
      alert('George I only reigned for 13 years.')
      return
    regnalyear+=1713
    if month<8: regnalyear+=1
  elif monarch=='GeorgeII':
    if regnalyear>34:
      alert('George II only reigned for 34 years.')
      return
    if regnalyear>26:
      regnalyear+=1726
    if month==6 and day<22: regnalyear+=1
    if month<6: regnalyear+=1
    if regnalyear<27:
      regnalyear+=1726
    if month==6 and day<11: regnalyear+=1
    if month<6: regnalyear+=1
  elif monarch=='GeorgeIII':
    if regnalyear>60:
      alert('George III only reigned for 60 years.')
      return
    regnalyear+=1759
    if month==10 and day<25: regnalyear+=1
    if month<10: regnalyear+=1
  
  elif monarch=='GeorgeIV':
    if regnalyear>11:
      alert('George III only reigned for 11 years.')
      return
    regnalyear+=1819
    if month==1 and day<29: regnalyear+=1
  
  elif monarch=='WilliamIV':
    if regnalyear>7:
      alert('William IV only reigned for 7 years.')
      return
    regnalyear+=1829
    if month==6 and day<26: regnalyear+=1
    if month<6: regnalyear+=1
  
  elif monarch=='Victoria':
    if regnalyear>64:
      alert('Victoria only reigned for 64 years.')
      return
    regnalyear+=1836
    if month==6 and day<20: regnalyear+=1
    if month<6: regnalyear+=1

  elif monarch=='EdwardVII':
    if regnalyear>10:
      alert('Edward VII only reigned for 10 years.')
      return
    regnalyear+=1900
    if month==1 and day<22: regnalyear+=1

  elif monarch=='GeorgeV':
    if regnalyear>26:
      alert('George V only reigned for 26 years.')
      return
    regnalyear+=1909
    if month==5 and day<6: regnalyear+=1
    if month<5: regnalyear+=1

  elif monarch=='GeorgeVI':
    if regnalyear>16:
      alert('George VI only reigned for 16 years.')
      return
    regnalyear+=1935
    if month==12 and day<11: regnalyear+=1
    if month<12: regnalyear+=1

  elif monarch=='ElizabethII':
    regnalyear+=1951
    if month==2 and day<6: regnalyear+=1
    if month<2: regnalyear+=1

  elif monarch=='EdwardVIII':
    alert('Edward VIII only reigned from Jan 20 to December 11, 1936.')
    regnalyear=1936

  elif monarch=='John':
    #alert('John was crowned on Ascension day in 1199. His regnal years run from one Ascension day to the next and are thus highly irregular. Use the Ecclesiastical calendar page to calculate Ascension day')
    #regnalyear='error'
    regnalyear+=1199 # Keith Briggs 2014-08-29 kludge

  elif monarch=='Jane':
    alert('Jane only ruled from July 6th to July 19th, 1553')
    regnalyear='error'

  if regnalyear<1753 :
    if month==3 and day<25:
      NS=regnalyear
      NS=NS%10
      regnalyear=regnalyear-1
      regnalyear=regnalyear+'/'+NS

  if month<3:
    NS=regnalyear % 10
    if NS==0: NS=regnalyear%100
    if NS==0: NS=regnalyear
    regnalyear-=1
    regnalyear=str(regnalyear)+'/'+str(NS)
  return regnalyear

if __name__=='__main__':
  x=parse_regnal_year_spec('23 Ed 1')
  print(x)
  print(get_regnalyear(x[0],x[1]+str(x[2])))
