// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.


#include <IFSelect_SelectSignature.hxx>
#include <IFSelect_Signature.hxx>
#include <IFSelect_SignCounter.hxx>
#include <Interface_Graph.hxx>
#include <Interface_InterfaceModel.hxx>
#include <Standard_Transient.hxx>
#include <Standard_Type.hxx>
#include <TCollection_AsciiString.hxx>

IMPLEMENT_STANDARD_RTTIEXT(IFSelect_SelectSignature,IFSelect_SelectExtract)

//  theexact : -1  OUI   0  NON une seule valeur  > 0 NON nb de valeurs
//  signmode : 1 prendre si contenu, 2 refuser si contenu
//             3 prendre si egal,    4 refuser si egal
//  ou test numerique, ajouter : 16 <  24 <=  32 >  40 >=
static Standard_Integer multsign
  (const TCollection_AsciiString& signtext,
   TColStd_SequenceOfAsciiString& signlist,
   TColStd_SequenceOfInteger&     signmode)
{
  Standard_Integer i, nb = signtext.Length(), mode = 0;
  for (i = 1; i <= nb; i ++) {
    char unsign = signtext.Value(i);
    if (unsign == '|' || unsign == '!' || unsign == '=') { mode = 1; break; }
    if (unsign == '<' || unsign == '>') { mode = 1; break; }
  }
  if (mode == 0) return mode;
//  On va tronconner
  TCollection_AsciiString item;  Standard_Integer imod = 1;
  for (i = 1; i <= nb; i ++) {
    char unsign = signtext.Value(i);
    if (unsign == '|' || unsign == '!') {
      if (item.Length() > 0) {
	signlist.Append (item);
	signmode.Append (imod);
	item.Clear();
	mode ++;
      }
      imod = (unsign == '|' ? 1 : 2);
    }
    else if (unsign == '<') imod += 16;
    else if (unsign == '>') imod += 32;
    else if (unsign == '=') { if (imod < 8) imod += 2; else imod += 8; }
    else item.AssignCat (unsign);
  }
  if (item.Length() > 0) {
    signlist.Append (item);
    signmode.Append (imod);
//    mode ++;  valait un au depart
  }
  return mode;
}



    IFSelect_SelectSignature::IFSelect_SelectSignature
  (const Handle(IFSelect_Signature)& matcher,
   const TCollection_AsciiString& signtext, const Standard_Boolean exact)
    : thematcher (matcher) , thesigntext (signtext) , theexact (exact ? -1 : 0)
{  if (!exact) theexact = multsign (thesigntext,thesignlist,thesignmode);  }

    IFSelect_SelectSignature::IFSelect_SelectSignature
  (const Handle(IFSelect_Signature)& matcher,
   const Standard_CString signtext, const Standard_Boolean exact)
    : thematcher (matcher) , thesigntext (signtext) , theexact (exact ? -1 : 0)
{  if (!exact) theexact = multsign (thesigntext,thesignlist,thesignmode);  }

    IFSelect_SelectSignature::IFSelect_SelectSignature
  (const Handle(IFSelect_SignCounter)& counter,
   const Standard_CString signtext, const Standard_Boolean exact)
    : thecounter (counter) , thesigntext (signtext) , theexact (exact ? -1 : 0)
{  if (!exact) theexact = multsign (thesigntext,thesignlist,thesignmode);  }

    Handle(IFSelect_Signature)  IFSelect_SelectSignature::Signature () const
      {  return thematcher;  }

    Handle(IFSelect_SignCounter)  IFSelect_SelectSignature::Counter () const
      {  return thecounter;  }


    Standard_Boolean  IFSelect_SelectSignature::SortInGraph
  (const Standard_Integer , const Handle(Standard_Transient)& ent,
   const Interface_Graph& G) const
{
  Standard_Boolean res;
  Standard_CString txt;
  const Handle(Interface_InterfaceModel)& model = G.Model();
  if (theexact <= 0) {
    if (!thematcher.IsNull()) return thematcher->Matches (ent,model,thesigntext, (theexact < 0));
    txt = thecounter->ComputedSign(ent,G);
    return IFSelect_Signature::MatchValue (txt,thesigntext , (theexact < 0));
  }

//  sinon : liste
//  Analyse en sequence : si alternance prend/prend-pas, le dernier a raison
//   en consequence, si que des prend ou que des prend-pas, c est commutatif
//   DONC recommendation : mettre les prend-pas en fin

//  AU DEPART : prendre = ne prendre que. prend-pas = prend-tout-sauf ...
//  Donc si le premier est un prend-pas, je commence par tout prendre
  Standard_Integer hmod = thesignmode.Value(1);
  Standard_Integer jmod = hmod/8;
  Standard_Integer imod = hmod - (jmod*8);
  res = (imod == 2 || imod == 4);
  for (Standard_Integer i = 1; i <= theexact; i ++) {
    Standard_CString signtext = thesignlist.Value(i).ToCString();
    hmod = thesignmode.Value(i);
    jmod = hmod/8;
    imod = hmod - (jmod*8);
    Standard_Boolean quid;
    if (jmod == 0) {
      if (!thematcher.IsNull()) quid = thematcher->Matches (ent,model,signtext,(imod > 2));
      else quid = IFSelect_Signature::MatchValue
	( thecounter->ComputedSign(ent,G),signtext, (imod > 2) );
    }
    else {
      if (!thematcher.IsNull()) txt = thematcher->Value (ent,model);
      else txt = thecounter->ComputedSign (ent,G);

      Standard_Integer val = atoi(txt);
      Standard_Integer lav = atoi (signtext);
      switch (jmod) {
        case 2 : quid = (val <  lav); break;
        case 3 : quid = (val <= lav); break;
        case 4 : quid = (val >  lav); break;
        case 5 : quid = (val >= lav); break;
	default : quid = Standard_False; break;
      }
    }
    if ((imod == 1 || imod == 3) && quid) res = Standard_True;
    if ((imod == 2 || imod == 4) && quid) res = Standard_False;
  }
  return res;
}

    Standard_Boolean  IFSelect_SelectSignature::Sort
  (const Standard_Integer , const Handle(Standard_Transient)& /*ent*/,
   const Handle(Interface_InterfaceModel)& /*model*/) const
{  return Standard_True;  }

    const TCollection_AsciiString&  IFSelect_SelectSignature::SignatureText () const
      {  return thesigntext;  }

    Standard_Boolean  IFSelect_SelectSignature::IsExact () const
      {  return (theexact < 0);  }

    TCollection_AsciiString  IFSelect_SelectSignature::ExtractLabel () const
{
  TCollection_AsciiString lab;
  if (!thematcher.IsNull()) lab.AssignCat (thematcher->Name());
  else                      lab.AssignCat (thecounter->Name());
  if      (theexact  < 0) lab.AssignCat(" matching ");
  else if (theexact == 0) lab.AssignCat(" containing ");
  else                    lab.AssignCat(" matching list ");
  lab.AssignCat(thesigntext);
  return lab;
}
