from browser import document as doc
from browser import alert, html

main = html.DIV(Class='content')
main <= html.H1('Calculs de lignes aériennes')
main <= html.HR()
doc <= html.DIV(main, Class='container')

# schema
main <= html.IMG(src='assets/img/schema.png', width='60%')

# table
table = html.TABLE(id='table', Class='table table-striped',
                   align='center', style={'width': '70%'})
main <= table

# table head
row = html.TR()
row <= html.TH('Valeur', style={'text-align': 'left', 'width': '45%'})
row <= html.TH('Exacte', style={'text-align': 'left'})
row <= html.TH('Approchée', style={'text-align': 'left'})
table <= html.THEAD(row)

# table body
tbody = html.TBODY()
table <= tbody

# portee
row = html.TR()
sp = html.SPAN('100', id='portee', contentEditable=True)
row <= (html.TH('Distance entre les supports (m)')
        + html.TD('$P=$ ' + sp, align='left', bgcolor='#b9ffb9') + html.TD())
tbody <= row

# dénivelé
row = html.TR()
sp = html.SPAN('0', id='denivele', contentEditable=True)
row <= (html.TH('Dénivelé (m)')
        + html.TD('$d=$ ' + sp, align='left', bgcolor='#b9ffb9') + html.TD())
tbody <= row

# hauteur
row = html.TR()
sp = html.SPAN('10', id='hauteur-support', contentEditable=True)
row <= (html.TH('Hauteur des supports (m)')
        + html.TD('$h=$ ' + sp, align='left', bgcolor='#b9ffb9') + html.TD())
tbody <= row

# masse lineique
row = html.TR()
sp = html.SPAN('100', id='masse-lineique', contentEditable=True)
row <= (html.TH('Masse linéique du câble (kg/km)')
        + html.TD('$\mu=$ ' + sp, align='left', bgcolor='#b9ffb9') + html.TD())
tbody <= row

# tension min
row = html.TR()
sp = html.SPAN('50', id='tension-min', contentEditable=True)
row <= (html.TH('Tension minimum dans le câble (daN)')
        + html.TD('$\sigma_{\min}=$ ' + sp, align='left', bgcolor='#b9ffb9')
        + html.TD())
tbody <= row

# tension max
row = html.TR()
sp = html.SPAN('', id='tension-max')
row <= (html.TH('Tension maximum dans le câble (daN)')
        + html.TD('$\sigma_{\max}=$ ' + sp, align='left')
        + html.TD(html.SPAN('$\sigma_{\max}≈$ ')
                  + html.SPAN(id='tension-max-approx'), align='left'))
tbody <= row

# paramètre
row = html.TR()
sp = html.SPAN('', id='parametre')
row <= (html.TH('Paramètre (m)') + html.TD('$a=$ ' + sp, align='left')
        + html.TD(html.SPAN('$a≈$ ') + html.SPAN(id='parametre-approx'),
                  align='left'))
tbody <= row

# flèche au point le plus bas
row = html.TR()
sp = html.SPAN('', id='fleche-bas')
row <= (html.TH('Flèche au point le plus bas (m)') + html.TD('$f=$ ' + sp,
                                                             align='left')
        + html.TD(html.SPAN('$f≈$ ') + html.SPAN(id='fleche-bas-approx'),
                  align='left'))
tbody <= row
tbody <= row

# flèche maximale
row = html.TR()
sp = html.SPAN('', id='fleche-max')
row <= (html.TH('Flèche maximale (m)') + html.TD('$F=$ ' + sp, align='left')
        + html.TD(html.SPAN('$F≈$ ') + html.SPAN(id='fleche-max-approx'),
                  align='left'))
tbody <= row

# longueur
row = html.TR()
sp = html.SPAN('', id='longueur')
row <= (html.TH('Longueur du câble (m)') + html.TD('$\ell=$ ' + sp,
                                                   align='left')
        + html.TD(html.SPAN('$\ell≈$ ') + html.SPAN(id='longueur-approx'),
                  align='left'))
tbody <= row

# coefficient de dilatation
row = html.TR()
sp = html.SPAN('23', id='lin-dilat', contentEditable=True)
row <= (html.TH('Coef. de dilatation (10<sup>-6</sup>K<sup>-1</sup>)')
        + html.TD('$\\alpha=$ ' + sp, align='left',
                  bgcolor='#b9ffb9') + html.TD())
tbody <= row

# écart de température
row = html.TR()
sp = html.SPAN('0', id='delta-t', contentEditable=True)
row <= (html.TH('Écart de température (°C)')
        + html.TD('$\Delta T=$ ' + sp, align='left',
                  bgcolor='#b9ffb9') + html.TD())
tbody <= row

# écart de paramètre
row = html.TR()
sp = html.SPAN('', id='delta-a')
row <= (html.TH('Écart de paramètre (m)')
        + html.TD('$\Delta a=$ ' + sp, align='left')
        + html.TD(html.SPAN('$\Delta a≈$ ')
                  + html.SPAN(id='delta-a-approx'), align='left'))
tbody <= row

# écart de flèche bas
row = html.TR()
sp = html.SPAN('', id='delta-f-bas')
row <= (html.TH('Écart de flèche au point le plus bas (m)')
        + html.TD('$\Delta f=$ ' + sp, align='left')
        + html.TD(html.SPAN('$\Delta f≈$ ')
                  + html.SPAN(id='delta-f-bas-approx'), align='left'))
tbody <= row

# écart de flèche bas
row = html.TR()
sp = html.SPAN('', id='delta-f-max')
row <= (html.TH('Écart de flèche maximale (m)')
        + html.TD('$\Delta F=$ ' + sp, align='left')
        + html.TD(html.SPAN('$\Delta F≈$ ')
                  + html.SPAN(id='delta-f-max-approx'), align='left'))
tbody <= row

# écart de longueur
row = html.TR()
sp = html.SPAN('', id='delta-l')
row <= (html.TH('Écart de longueur (m)')
        + html.TD('$\Delta \ell=$ ' + sp, align='left')
        + html.TD(html.SPAN('$\Delta \ell≈$ ')
                  + html.SPAN(id='delta-l-approx'), align='left'))
tbody <= row


main <= html.CANVAS(id='plot-area',
                    style={'padding-left': '0',
                           'padding-right': '0',
                           'margin-left': 'auto',
                           'margin-right': 'auto'},
                    width='800px', height='400px')

main <= html.BR()
# main <= html.SPAN('Formules (approchées) utilisées : '
#                   '$$f \\approx \dfrac{P^2}{8a}$$'
#                   '$$\ell \\approx P + \dfrac{P^3}{24 a^2}$$'
#                   '$$\Delta \ell = \ell\, \\alpha\, \Delta T '
#                   '\\approx P\, \\alpha\, \Delta T$$')

# MathJax reloader
reloader = html.SCRIPT()
reloader <= 'MathJax.Hub.Queue(["Typeset",MathJax.Hub])'
doc <= reloader


def get_value(id, neg=False):
    from assets.utils import smart_s2f
    try:
        v = smart_s2f(doc[id].text)
        if not neg and v < 0:
            raise ValueError()
        doc[id].style.color = 'black'
        return v
    except:
        doc[id].style.color = 'red'
        raise


def compute_and_update():
    from assets.utils import smart_f2s
    from assets import line

    try:
        # getting values
        P = get_value('portee')
        d = get_value('denivele', neg=True)
        h = get_value('hauteur-support')
        mu = get_value('masse-lineique') / 1000
        t0 = get_value('tension-min') * 10
        alpha = 1e-6 * get_value('lin-dilat')
        dT = get_value('delta-t', neg=True)

        # computing
        lia = line.LineApprox(P=P, d=d, mu=mu, t0=t0)
        lie = line.LineExact(P=P, d=d, mu=mu, t0=t0)
        
        lie_dil = lie.expand(alpha, dT)
        lia_dil = lia.expand(alpha, dT)

        # updating
        values = {'tension-max': lie.t_max / 10,
                  'tension-max-approx': lia.t_max / 10,
                  'parametre': lie.a,
                  'parametre-approx': lia.a,
                  'fleche-bas': lie.height_chord_lowest(),
                  'fleche-bas-approx': lia.height_chord_lowest(),
                  'fleche-max': lie.height_chord_max(),
                  'fleche-max-approx': lia.height_chord_max(),
                  'longueur': lie.length(),
                  'longueur-approx': lia.length(),
                  'delta-a': lie_dil.a - lie.a,
                  'delta-a-approx': lia_dil.a - lia.a,
                  'delta-f-bas': lie_dil.height_chord_lowest() - lie.height_chord_lowest(),
                  'delta-f-bas-approx': lia_dil.height_chord_lowest() - lia.height_chord_lowest(),
                  'delta-f-max': lie_dil.height_chord_max() - lie.height_chord_max(),
                  'delta-f-max-approx': lia_dil.height_chord_max() - lia.height_chord_max(),
                  'delta-l': lie_dil.length() - lie.length(),
                  'delta-l-approx': lia_dil.length() - lia.length()}
        
        for n, v in values.items():
            doc[n].text = smart_f2s(v)

        lis = [lie]
        if dT != 0:
            lis.append(lie_dil)
        draw(lis, h)

    except:
        raise
       # pass


def draw(lis, h):

    canvas = doc['plot-area']
    ctx = canvas.getContext('2d')

    def plot(xx, yy, linethick=1, color='black'):
        ctx.beginPath()
        ctx.moveTo(xx[0], yy[0])
        for x, y in zip(xx[1:], yy[1:]):
            ctx.lineTo(x, y)
        ctx.lineWidth = linethick
        ctx.strokeStyle = color
        ctx.stroke()

    def circle(x, y, radius, color='black'):
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, 2 * 3.1416, False);
        ctx.fillStyle = color
        ctx.closePath()
        ctx.fill()
    
    P = lis[0].P
    d = lis[0].d
    xA, xB = lis[0].xA, lis[0].xB
    yA, yB = lis[0].yA, lis[0].yB

    shift = 2
    canvas.height = int((canvas.width - 2 * shift) / P
                        * (h + abs(d))) + 1 + shift
    
    # clear
    ctx.setTransform(1, 0, 0, 1, 0, 0)
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    wi, he = canvas.width - 2 * shift, canvas.height - shift
    ctx.translate(shift, canvas.height)
    
    # scaling
    scale = min(wi / P, he / (h + abs(d)))
    ctx.scale(scale, -scale)
    ctx.translate(-xA, h - yA - min(d, 0))
    # posts
    plot([xA , xA], [yA - h, yA], linethick=2*shift / scale, color='black')
    plot([xB, xB], [yB - h, yB], linethick=2*shift / scale, color='black')
    circle(xA, yA, shift / scale)
    circle(xB, yB, shift / scale)

    colors = ['blue', 'green', 'red']
    c = 0
    for li in lis:
        xx, yy = li.sample()
        xx = [x - li.xA + lis[0].xA for x in xx]
        yy = [y - li.yA + lis[0].yA for y in yy]
        plot(xx, yy, linethick=1 / scale, color=colors[c])
        c = (c + 1) % len(colors)

# bindings
for f in ['portee', 'denivele', 'hauteur-support', 'masse-lineique',
          'tension-min', 'lin-dilat', 'delta-t']:
    doc[f].bind('input', compute_and_update)

compute_and_update()

# debug
print(doc.children[1].html)
