package maple2c_derivatives;

use List::Util 'all';
use Data::Dumper;

use Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(
maple2c_derivatives
);

1; # return true value

sub maple2c_derivatives
{
  my $derivative   = $_[0];
  my $type = $_[1];
  my @out_der = ();

  my @words = ("rho", "sigma", "lapl", "tau");
  my %partials = (
    "rho"   => [[[0, 0, 0, 0, 0, 0, 0, 0, 0]],    # 0th-order
                [[1, 0, 0, 0, 0, 0, 0, 0, 0],     # 1st-order
                 [0, 1, 0, 0, 0, 0, 0, 0, 0]],
                [[2, 0, 0, 0, 0, 0, 0, 0, 0],     # 2nd-order
                 [1, 1, 0, 0, 0, 0, 0, 0, 0],
                 [0, 2, 0, 0, 0, 0, 0, 0, 0]],
                [[3, 0, 0, 0, 0, 0, 0, 0, 0],     # 3rd-order
                 [2, 1, 0, 0, 0, 0, 0, 0, 0],
                 [1, 2, 0, 0, 0, 0, 0, 0, 0],
                 [0, 3, 0, 0, 0, 0, 0, 0, 0]],
                [[4, 0, 0, 0, 0, 0, 0, 0, 0],     # 4th-order
                 [3, 1, 0, 0, 0, 0, 0, 0, 0],
                 [2, 2, 0, 0, 0, 0, 0, 0, 0],
                 [1, 3, 0, 0, 0, 0, 0, 0, 0],
                 [0, 4, 0, 0, 0, 0, 0, 0, 0]],
    ],
    "sigma" => [[[0, 0, 0, 0, 0, 0, 0, 0, 0]],    # 0th-order
                [[0, 0, 1, 0, 0, 0, 0, 0, 0],     # 1st-order
                 [0, 0, 0, 1, 0, 0, 0, 0, 0],
                 [0, 0, 0, 0, 1, 0, 0, 0, 0]],
                [[0, 0, 2, 0, 0, 0, 0, 0, 0],     # 2nd-order
                 [0, 0, 1, 1, 0, 0, 0, 0, 0],
                 [0, 0, 1, 0, 1, 0, 0, 0, 0],
                 [0, 0, 0, 2, 0, 0, 0, 0, 0],
                 [0, 0, 0, 1, 1, 0, 0, 0, 0],
                 [0, 0, 0, 0, 2, 0, 0, 0, 0]],
                [[0, 0, 3, 0, 0, 0, 0, 0, 0],     # 3rd-order
                 [0, 0, 2, 1, 0, 0, 0, 0, 0],
                 [0, 0, 2, 0, 1, 0, 0, 0, 0],
                 [0, 0, 1, 2, 0, 0, 0, 0, 0],
                 [0, 0, 1, 1, 1, 0, 0, 0, 0],
                 [0, 0, 1, 0, 2, 0, 0, 0, 0],
                 [0, 0, 0, 3, 0, 0, 0, 0, 0],
                 [0, 0, 0, 2, 1, 0, 0, 0, 0],
                 [0, 0, 0, 1, 2, 0, 0, 0, 0],
                 [0, 0, 0, 0, 3, 0, 0, 0, 0]],
                [[0, 0, 4, 0, 0, 0, 0, 0, 0],     # 4th-order
                 [0, 0, 3, 1, 0, 0, 0, 0, 0],
                 [0, 0, 3, 0, 1, 0, 0, 0, 0],
                 [0, 0, 2, 2, 0, 0, 0, 0, 0],
                 [0, 0, 2, 1, 1, 0, 0, 0, 0],
                 [0, 0, 2, 0, 2, 0, 0, 0, 0],
                 [0, 0, 1, 3, 0, 0, 0, 0, 0],
                 [0, 0, 1, 2, 1, 0, 0, 0, 0],
                 [0, 0, 1, 1, 2, 0, 0, 0, 0],
                 [0, 0, 1, 0, 3, 0, 0, 0, 0],
                 [0, 0, 0, 4, 0, 0, 0, 0, 0],
                 [0, 0, 0, 3, 1, 0, 0, 0, 0],
                 [0, 0, 0, 2, 2, 0, 0, 0, 0],
                 [0, 0, 0, 1, 3, 0, 0, 0, 0],
                 [0, 0, 0, 0, 4, 0, 0, 0, 0]]
    ],
    "lapl" =>  [[[0, 0, 0, 0, 0, 0, 0, 0, 0]],    # 0th-order
                [[0, 0, 0, 0, 0, 1, 0, 0, 0],     # 1st-order
                 [0, 0, 0, 0, 0, 0, 1, 0, 0]],
                [[0, 0, 0, 0, 0, 2, 0, 0, 0],     # 2nd-order
                 [0, 0, 0, 0, 0, 1, 1, 0, 0],
                 [0, 0, 0, 0, 0, 0, 2, 0, 0]],
                [[0, 0, 0, 0, 0, 3, 0, 0, 0],     # 3rd-order
                 [0, 0, 0, 0, 0, 2, 1, 0, 0],
                 [0, 0, 0, 0, 0, 1, 2, 0, 0],
                 [0, 0, 0, 0, 0, 0, 3, 0, 0]],
                [[0, 0, 0, 0, 0, 4, 0, 0, 0],     # 4th-order
                 [0, 0, 0, 0, 0, 3, 1, 0, 0],
                 [0, 0, 0, 0, 0, 2, 2, 0, 0],
                 [0, 0, 0, 0, 0, 1, 3, 0, 0],
                 [0, 0, 0, 0, 0, 0, 4, 0, 0]]
    ],
    "tau"  =>  [[[0, 0, 0, 0, 0, 0, 0, 0, 0]],    # 0th-order
                [[0, 0, 0, 0, 0, 0, 0, 1, 0],     # 1st-order
                 [0, 0, 0, 0, 0, 0, 0, 0, 1]],
                [[0, 0, 0, 0, 0, 0, 0, 2, 0],     # 2nd-order
                 [0, 0, 0, 0, 0, 0, 0, 1, 1],
                 [0, 0, 0, 0, 0, 0, 0, 0, 2]],
                [[0, 0, 0, 0, 0, 0, 0, 3, 0],     # 3rd-order
                 [0, 0, 0, 0, 0, 0, 0, 2, 1],
                 [0, 0, 0, 0, 0, 0, 0, 1, 2],
                 [0, 0, 0, 0, 0, 0, 0, 0, 3]],
                [[0, 0, 0, 0, 0, 0, 0, 4, 0],     # 4th-order
                 [0, 0, 0, 0, 0, 0, 0, 3, 1],
                 [0, 0, 0, 0, 0, 0, 0, 2, 2],
                 [0, 0, 0, 0, 0, 0, 0, 1, 3],
                 [0, 0, 0, 0, 0, 0, 0, 0, 4]]
                ]
      );

  # finds out the order of each partial
  my %order = ();
  my $total_order = 0;
  foreach $word (@words){
    $order{$word} = 0;
    if($derivative =~ /$word([0-9]*)/){
      $order{$word} = $1 == "" ? 1 : int($1);
      $total_order += $order{$word};
    }
  }

  my %n_var = ("lda" => 2, "gga" => 5, "mgga" => 9);
  my $max_n = $n_var{$type};

  my @all_derivatives = ();
  my $der_n = 0;
  for(my $n_rho=0; $n_rho <= $#{$partials{"rho"}[$order{"rho"}]}; $n_rho++){
    for(my $n_sigma=0; $n_sigma <= $#{$partials{"sigma"}[$order{"sigma"}]}; $n_sigma++){
      for(my $n_lapl=0; $n_lapl <= $#{$partials{"lapl"}[$order{"lapl"}]}; $n_lapl++){
        for(my $n_tau=0; $n_tau <= $#{$partials{"tau"}[$order{"tau"}]}; $n_tau++){
          # sum orders in all variables

          my @final_der = (0) x $max_n;
          for(my $i=0; $i<$max_n; $i++){
            $final_der[$i] +=
                $partials{"rho"}[$order{"rho"}][$n_rho][$i] +
                $partials{"sigma"}[$order{"sigma"}][$n_sigma][$i] +
                $partials{"lapl"}[$order{"lapl"}][$n_lapl][$i] +
                $partials{"tau"}[$order{"tau"}][$n_tau][$i];
          }
          push @all_derivatives, [\@final_der, $derivative."_".($der_n++)."_"];
        }
      }
    }
  }

  return @all_derivatives;
}
