#include "ft_sl_decl.h"

void mainloop (
               Bool &success, Env &env)
{
  int pe=env.pre.pe;
  Alias (PartOne, ALL1,env.pre.ALL1);
  Alias (PartOne, ONE1,env.pre.ONE1);
  Alias (PartNP, ONEn,env.pre.ONEn);
  Alias (PartNP, PPEn,env.pre.PPEn);
  Alias (SwapOne, SwONE2ALL1,env.pre.SwONE2ALL1);
  Alias (SwapNP, SwPPE2ONEn,env.pre.SwPPE2ONEn);
  Alias (Setup, sp,env.sp);
  Alias (Int, niter,env.niter);
  Alias (Int, fdir,env.fdir);
  Alias (Int, finv,env.finv);
  Alias (Int, lay1d,env.lay1d);
  Alias (MPartRange3D, mdom0,env.mdom0);
  Alias (MPartRange3D, mdom1,env.mdom1);
  Alias (MPartRange3D, mdom2,env.mdom2);
  Alias (PartRange3D, dom0,env.dom0);
  Alias (PartRange3D, dom1,env.dom1);
  Alias (PartRange3D, dom2,env.dom2);
  Alias (MSwapRange3D, sw01,env.sw01);
  Alias (MSwapRange3D, sw12,env.sw12);
  Alias (MSwapRange3D, sw21,env.sw21);
  Alias (MSwapRange3D, sw10,env.sw10);
  Alias (MSwapRange3D, sw02,env.sw02);
  Alias (MSwapRange3D, sw20,env.sw20);
  Data (Int, iter);
  Data (Checksums, cksum);
  Data (Int, cond);
  Data (Cplx, c2e);
  Data (Vector3Dcplx, u0_dom2);
  Data (Vector3Dcplx, u2_dom0);
  Data (Vector3Dcplx, u2_dom1);
  Data (Vector3Dcplx, u2_dom2);
  Data (ArrayCplx, c1e_ONEn);
  Data (ArrayCplx, c1e_PPEn);

  swapSetup (SwONE2ALL1, success, success, 0, 7, pe);
  Alloc (c1e_ONEn, ONEn[pe]);
  Alloc (c1e_PPEn, PPEn[pe]);
  Alloc (u0_dom2, dom2[pe]);
  Alloc (u2_dom0, dom0[pe]);
  Alloc (u2_dom1, dom1[pe]);
  Alloc (u2_dom2, dom2[pe]);

  swapSetupAM (sw02, u2_dom0, u0_dom2, 0, 0, pe);

  swapSetupAM (sw01, u2_dom0, u2_dom1, 0, 1, pe);

  swapSetupAM (sw12, u2_dom1, u0_dom2, 0, 2, pe);

  swapSetupAM (sw20, u2_dom2, u2_dom0, 0, 3, pe);

  swapSetupAM (sw21, u2_dom2, u2_dom1, 0, 4, pe);

  swapSetupAM (sw10, u2_dom1, u2_dom0, 0, 5, pe);

  swapSetup (SwPPE2ONEn, c1e_PPEn, c1e_ONEn, 0, 6, pe);

  init_checksums (sp, cksum);

  compute_init_cond (sp, dom0[pe], u2_dom0);

  cffts1 (sp, fdir, u2_dom0 /* mod */, dom0[pe]);

  if (lay1d)
  {
      cffts2 (sp, fdir, u2_dom0 /* mod */, dom0[pe]);

      swapBeginAM (sw02, u2_dom0, u0_dom2, 0, 0, pe);

      for (int _mi=0; _mi<mdom2.getNo(pe); _mi++)
      {
          swapEndAM (sw02, u2_dom0, u0_dom2, _mi, 0, 0, pe);

          cffts3 (sp, fdir, u0_dom2 /* mod */, mdom2.idx(pe,_mi));
      }
  }
  else
  {
      swapBeginAM (sw01, u2_dom0, u2_dom1, 0, 1, pe);

      for (int _mi=0; _mi<mdom1.getNo(pe); _mi++)
      {
          swapEndAM (sw01, u2_dom0, u2_dom1, _mi, 0, 1, pe);

          cffts2 (sp, fdir, u2_dom1 /* mod */, mdom1.idx(pe,_mi));
      }

      swapBeginAM (sw12, u2_dom1, u0_dom2, 0, 2, pe);

      for (int _mi=0; _mi<mdom2.getNo(pe); _mi++)
      {
          swapEndAM (sw12, u2_dom1, u0_dom2, _mi, 0, 2, pe);

          cffts3 (sp, fdir, u0_dom2 /* mod */, mdom2.idx(pe,_mi));
      }
  }

  for (iter=0, cond=1; cond; iter++)
  {
      evolve (sp, iter, u0_dom2, dom2[pe], u2_dom2);

      cffts3 (sp, finv, u2_dom2 /* mod */, dom2[pe]);

      if (lay1d)
      {
          swapBeginAM (sw20, u2_dom2, u2_dom0, 0, 3, pe);

          for (int _mi=0; _mi<mdom0.getNo(pe); _mi++)
          {
              swapEndAM (sw20, u2_dom2, u2_dom0, _mi, 0, 3, pe);

              cffts2 (sp, finv, u2_dom0 /* mod */, mdom0.idx(pe,_mi));
          }

          cffts1 (sp, finv, u2_dom0 /* mod */, dom0[pe]);
      }
      else
      {
          swapBeginAM (sw21, u2_dom2, u2_dom1, 0, 4, pe);

          for (int _mi=0; _mi<mdom1.getNo(pe); _mi++)
          {
              swapEndAM (sw21, u2_dom2, u2_dom1, _mi, 0, 4, pe);

              cffts2 (sp, finv, u2_dom1 /* mod */, mdom1.idx(pe,_mi));
          }

          swapBeginAM (sw10, u2_dom1, u2_dom0, 0, 5, pe);

          for (int _mi=0; _mi<mdom0.getNo(pe); _mi++)
          {
              swapEndAM (sw10, u2_dom1, u2_dom0, _mi, 0, 5, pe);

              cffts1 (sp, finv, u2_dom0 /* mod */, mdom0.idx(pe,_mi));
          }
      }

      checksum_dom (u2_dom0, dom0[pe], c1e_PPEn[pe]);

      swapBegin (SwPPE2ONEn, c1e_PPEn, c1e_ONEn, 0, 6, pe);

      econd (niter, iter, cond);

      swapEnd (SwPPE2ONEn, c1e_PPEn, c1e_ONEn, 0, 6, pe);

      if (ONE1.getNo(pe))
      {
          sumproc (c1e_ONEn, ONEn[pe], c2e);
      }

      if (ONE1.getNo(pe))
      {
          checksum_set (sp, c2e, iter, cksum /* mod */);
      }
  }

  if (ONE1.getNo(pe))
  {
      verify (sp, cksum, success);
  }

  swapBegin (SwONE2ALL1, success, success, 0, 7, pe);

  swapEnd (SwONE2ALL1, success, success, 0, 7, pe);
}


