// Copyright (C) 2014 ULg-UCL
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished
// to do so, provided that the above copyright notice(s) and this
// permission notice appear in all copies of the Software and that
// both the above copyright notice(s) and this permission notice
// appear in supporting documentation.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
// OF THIS SOFTWARE.
//
// Please report all bugs and problems to the public mailing list
// <gmsh@geuz.org>.
//
// Contributors: Thomas Toulorge, Jonathan Lambrechts

#ifndef _MESHOPTCOMMON_H_
#define _MESHOPTCOMMON_H_

#include <vector>


class MElement;
class GEntity;
class SPoint3;
class ObjContrib;


class MeshOptPatchDef {
public:
  enum { STRAT_DISJOINT, STRAT_ONEBYONE };
  int strategy;                                         // Strategy: disjoint patches or adaptive one-by-one
  int minLayers, maxLayers;                             // Min. and max. nb. of layers around a bad element in patch
  union {
    struct {                                            // If adaptive strategy:
      int maxPatchAdapt;                                // Max. nb. of adaptation iterations
      int maxLayersAdaptFact;                           // Growth rate in number of layers around a bad element
      double distanceAdaptFact;                         // Growth rate in max. distance from bad element
    };
    bool weakMerge;                                     // If disjoint strategy: weak or strong merging of patches
  };
  virtual ~MeshOptPatchDef() {}
  virtual double elBadness(MElement *el,                // Determine "badness" of a given element (for patch creation)
                           GEntity* gEnt) const = 0;
  virtual double bndElBadness(MElement *el,             // Determine "badness" of a given boundary element (for patch creation)
                              GEntity* gEnt) const = 0;
  virtual double maxDistance(MElement *el) const = 0;   // Compute max. distance to a given bad element for elements in patch
  virtual int inPatch(const SPoint3 &badBary,           // Determine whether a given element should be included in the patch around a...
                      double limDist,                   // ... given bad element barycenter, with a limit distance if needed. Output: ...
                      MElement *el,                     // ... -1 = excluded, 0 = included only up to minLayers, 1 = included up to maxLayers
                      GEntity* gEnt) const = 0;
protected:
  bool testElInDist(const SPoint3 &P, double limDist,   // Test whether an element is within a certain distance from a point
                    MElement *el) const;
};


struct MeshOptPass {                                    // Parameters controlling the optimization procedure in each pass
  std::vector<ObjContrib*> contrib;                     // Indices of contributions to objective function
  int maxOptIter;                                       // Max. number of opt. iterations each time the barrier is moved
  int maxParamUpdates;                                  // Max. number of times the obj. func. parameters are updated (i.e. the barrier is moved)
};


struct MeshOptParameters {                              // Parameters controlling the strategy
  int dim ;                                             // Which dimension to optimize
  bool onlyVisible ;                                    // Apply optimization to visible entities ONLY
  bool fixBndNodes;                                     // If points can move on boundaries
  bool useGeomForPatches, useGeomForOpt;                // Whether to use info from CAD for creation of patches and for optimization
  bool useBoundaries;                                   // Whether to use boundary elements
  MeshOptPatchDef *patchDef;
  std::vector<MeshOptPass> pass;
  int displayInterv;                                    // Sampling rate in opt. iterations for display
  int verbose;                                          // Level of information displayed and written to disk
  int success;                                          // Success flag: -1 = fail, 0 = partial fail (target not reached), 1 = success
  double CPU;                                           // Time for optimization
};


#endif
