"""Generate Fortran WENO kernels with PyWENO."""

# Copyright (c) 2011, 2014 Matthew Emmett.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#   1. Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#
#   2. Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials provided
#      with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import numpy as np
import pyweno

kernel = pyweno.kernels.KernelGenerator('fortran')

#### set fortran templatese to match clawpack

template = '''
subroutine {function}(q, ql, qr, num_eqn, maxnx, num_ghost)

  implicit none

  integer,          intent(in)  :: num_eqn, maxnx, num_ghost
  double precision, intent(in)  :: q(num_eqn,maxnx+2*num_ghost)
  double precision, intent(out) :: ql(num_eqn,maxnx+2*num_ghost), qr(num_eqn,maxnx+2*num_ghost)

  integer :: i, m
  double precision :: {variables}

  do i = num_ghost, maxnx+num_ghost+1
    do m = 1, num_eqn
      {kernel}
    end do
  end do

end subroutine
'''

class FGenerator(pyweno.symbols.FGenerator):
  def __getitem__(self, idx):
    return pyweno.symbols.real('q(m,i{:+d})'.format(idx))

class FStarGenerator(pyweno.symbols.FStarGenerator):
  def __getitem__(self, idx):
    return pyweno.symbols.real([ 'ql(m,i)', 'qr(m,i)' ][idx])

pyweno.symbols.f  = FGenerator()
pyweno.symbols.fs = FStarGenerator()


#### open weno.f90 and write header

out = open('weno.f90', 'w')
out.write('''! This file was generated by: python weno.py
module weno
contains
''')


#### generate and write reconstruction functions for cell boundaries

for k in range(3, 3):

  print('generating reconstruction for k: %02d' % k)

  # smoothness
  beta = pyweno.symbolic.jiang_shu_smoothness_coefficients(k)

  # reconstructions: -1=left, 1=right
  varpi, split = pyweno.symbolic.optimal_weights(k, [ -1, 1 ])
  coeffs = pyweno.symbolic.reconstruction_coefficients(k, [ -1, 1 ])

  body = []
  body.append(kernel.smoothness(beta=beta))
  body.append(kernel.weights(varpi=varpi, split=split))
  body.append(kernel.reconstruction(coeffs=coeffs))

  variables = []
  variables.extend([ x['name'] for x in pyweno.symbols.sigma.all(k) ])
  variables.extend([ x['name'] for x in pyweno.symbols.omega.all(2, k, split) ])
  variables.extend([ x['name'] for x in pyweno.symbols.fr.all(2, k) ])

  # write function
  out.write(template.format(
      function='weno%d' % (2*k-1),
      variables=', &\n'.join(variables),
      kernel='\n'.join(body)))
