/* Copyright (c) 2018
   Charles Jordan (Hokkaido University, Sapporo, Japan),
   Michael Joswig, Lars Kastner (Technische Universitaet Berlin, Germany)

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 3, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
-----------------------------------------------------------------------------
*/

#ifndef FLIPDATA_SYM_HH
#define FLIPDATA_SYM_HH
#include "FlipData_enhanced.hh"



template<typename FlipChecker, typename APCType>
class FlipDataSym: public FlipData_enhanced<FlipChecker, APCType,FlipDataSym<FlipChecker,APCType>>{
   friend class FlipData_enhanced<FlipChecker,APCType,FlipDataSym<FlipChecker,APCType>>;
   using pmFlipContainer = typename FlipData_enhanced<FlipChecker, APCType,FlipDataSym<FlipChecker,APCType>>::pmFlipContainer;

   private:
      // properties:


      // methods:
      int is_lex_upflip(Flip flip, const TriangNode& target, gkz_vector_type& result_gkz){
         int result;
         result = this->apc.evaluate_flip(flip, this->source_optimal, target, result_gkz);
         return result;
      }


      void insert_flip(Flip flip, gkz_vector_type flip_gkz, int isUpflip){
         if(isUpflip == 1){
            if(!this->upflips.exists(flip_gkz)){
               this->upflips[flip_gkz] = flip;
            }
         } else if(isUpflip == -1){
            if(!this->downflips.exists(flip_gkz)){
               this->downflips[flip_gkz] = flip;
            }
         }
      }
      

      TriangNode get_target_triangulation(const Flip& flip) const{
         return this->apc.get_sbb().get_canonical_representative(TriangNode(0, this->source_triang, flip));
      }

      void optimize_source(){
         this->source_optimal = this->apc.get_sbb().get_canonical_representative(this->source_triang);
      }
      
      // Mutation constructor, should not be public
      FlipDataSym(
            const APCType& apc_in,
            TriangNode triang,
            const pmFlipContainer& uf,
            const pmFlipContainer& df,
            const std::list<Flip>& af,
            const FlipChecker& fc_in
            ): FlipData_enhanced<FlipChecker, APCType, FlipDataSym>(apc_in, triang, uf, df, af, fc_in)
         {
            optimize_source();
         }

   public:
      typedef FlipDataSym<typename FlipChecker::Initial, APCType> Initial;
      typedef FlipChecker Checker;

      FlipDataSym(
            const APCType& apc_in,
            TriangNode triang,
            const FlipChecker& fc_in
            ): FlipData_enhanced<FlipChecker, APCType, FlipDataSym>(apc_in, triang, fc_in)
         {
            optimize_source();
            this->_add_new_flips(this->source_triang);
            this->populate();
         }


//      FlipDataSym mutate(const Flip& flip, const TriangNode& target){
//         FlipDataSym result(this->apc, target, this->upflips, this->downflips, this->all_flips, this->fc);
//         result.mutate_inner(flip);
//         return result;
//      }

};


#endif
