#ifdef DOC_BUILD_INTERNAL
#endif
#include "ntwfo.h"
void ntwfo_DeleteTmpPropagations(NTWFO Ntwfo)
{
  unsigned i;
  for (i = 0; i < array_GetSize(Ntwfo->tmpPropagations); i++) {
    Ntwfo->substsToDelete = array_Add(Ntwfo->mem, Ntwfo->substsToDelete, (intptr_t)((NTWFO_PROPAGATION)array_GetElement(Ntwfo->tmpPropagations, i))->subst);
    memory_Free(Ntwfo->mem, (NTWFO_PROPAGATION)array_GetElement(Ntwfo->tmpPropagations, i), sizeof(struct NTWFO_PROPAGATION_HELP));
  }
  array_Clean(Ntwfo->tmpPropagations);
}
void ntwfo_ShareSubst(NTWFO Ntwfo, SUBST Subst)
{
  unsigned i;
  for (i = 0; i < subst_NumberOfVariables(Subst); i++) {
    if (subst_VarDefined(Subst, (SYMBOL)i) && !sharing_IsShared(subst_GetValue(Subst, (SYMBOL)i))) {
      subst_SetValue(Subst, (SYMBOL)i, sharing_GetSharedTerm(Ntwfo->sharer, subst_GetValue(Subst, (SYMBOL)i)));
    }
  }
}
SUBST ntwfo_GenerateUnit(NTWFO Ntwfo, CLAUSE Clause)
{
  unsigned i;
  SUBST result;
  if (clause_GetPremiseLiterals(Clause) && clause_GetConclusionLiterals(Clause)) {
    return NULL;
  }
  if (clause_GetFolLiterals(Clause) == 1) {
    return subst_Create(Ntwfo->mem, clause_GetVariables(Clause));
  }
  subst_ContextStart(Ntwfo->subststate, Ntwfo->symbstate);
  for (i = 1; i < clause_GetFolLiterals(Clause); i++) {
    if (!subst_TermUnifyIdenticalVarsNoTypes(Ntwfo->subststate, Ntwfo->termstate, Ntwfo->symbstate, clause_GetAtom(Clause, 0), clause_GetAtom(Clause, i), TRUE)) {
      subst_ContextStop(Ntwfo->subststate);
      return NULL;
    }
  }
  result = subst_ContextFlattenExtractSubst(Ntwfo->subststate, Ntwfo->termstate, Ntwfo->symbstate, clause_GetVariables(Clause));
  subst_ContextStop(Ntwfo->subststate);
  ntwfo_ShareSubst(Ntwfo, result);
  return result;
}
BOOL ntwfo_CheckClause(NTWFO Ntwfo, TRAIL Trail, CLAUSE Clause, unsigned I, unsigned Prop, BOOL TrueOnPropagation, unsigned Trailsize)
{
  unsigned j;
  SUBST tmp;
  TERM cur, sharedVersion, trailAtom;
  TRAILDATA traildata;
  ARRAY instances;
  NTWFO_PROPAGATION prop;
  if (I == clause_GetFolLiterals(Clause)) {
    if (Prop == clause_GetFolLiterals(Clause)) return TRUE;
    sharedVersion = sharing_GetSharedTerm(Ntwfo->sharer, subst_ContextFlattenTermApplyToTerm(Ntwfo->subststate, Ntwfo->termstate, clause_GetAtom(Clause, Prop)));
    if (term_IsGround(Ntwfo->termstate, sharedVersion)) {
      traildata = trail_AtomData(Trail, sharedVersion, NULL);
      if (traildata != NULL && trail_AtomTrailPositionFromData(Trail, traildata) < Trailsize) {
        return FALSE;
      }
    }
    if (TrueOnPropagation) return TRUE;
    tmp = subst_ContextFlattenExtractSubst(Ntwfo->subststate, Ntwfo->termstate, Ntwfo->symbstate, clause_GetVariables(Clause));
    ntwfo_ShareSubst(Ntwfo, tmp);
    prop = memory_Malloc(Ntwfo->mem, sizeof(struct NTWFO_PROPAGATION_HELP));
    prop->clause = Clause, prop->subst = tmp, prop->idx = Prop, prop->trailsize = Trailsize;
    Ntwfo->tmpPropagations = array_Add(Ntwfo->mem, Ntwfo->tmpPropagations, (intptr_t)prop);
    return FALSE;
  }
  cur = clause_GetAtom(Clause, I);
  sharedVersion = sharing_GetSharedTerm(Ntwfo->sharer, subst_ContextFlattenTermApplyToTerm(Ntwfo->subststate, Ntwfo->termstate, cur));
  if (term_IsGround(Ntwfo->termstate, sharedVersion)) {
    traildata = trail_AtomData(Trail, sharedVersion, NULL);
    if (traildata != NULL && trail_AtomTrailPositionFromData(Trail, traildata) < Trailsize) {
      if (trail_IsPositiveFromData(Trail, traildata) != (I < clause_GetPremiseLiterals(Clause))) return FALSE;
      else return ntwfo_CheckClause(Ntwfo, Trail, Clause, I+1, Prop, TrueOnPropagation, Trailsize);
    } else {
      if (Prop == clause_GetFolLiterals(Clause)) {
        return ntwfo_CheckClause(Ntwfo, Trail, Clause, I+1, I, TrueOnPropagation, Trailsize);
      }
      if ((Prop < clause_GetPremiseLiterals(Clause)) != (I < clause_GetPremiseLiterals(Clause))) return FALSE;
      subst_ContextStackPush(Ntwfo->subststate);
      if (!subst_TermUnifyIdenticalVarsNoTypesStack(Ntwfo->subststate, Ntwfo->termstate, Ntwfo->symbstate, clause_GetAtom(Clause, Prop), clause_GetAtom(Clause, I), TRUE)) {
        subst_ContextStackPop(Ntwfo->subststate);
        return FALSE;
      }
      if (ntwfo_CheckClause(Ntwfo, Trail, Clause, I+1, Prop, TrueOnPropagation, Trailsize)) return TRUE;
      subst_ContextStackPop(Ntwfo->subststate);
      return FALSE;
    }
  }
  instances = array_Create(Ntwfo->mem, 3);
  if (I < clause_GetPremiseLiterals(Clause)) distrn_SearchInstances(Ntwfo->mem, Ntwfo->postraillits, Ntwfo->termstate, sharedVersion, &instances);
  else distrn_SearchInstances(Ntwfo->mem, Ntwfo->negtraillits, Ntwfo->termstate, sharedVersion, &instances);
  for (j = 0; j < array_GetSize(instances); j++) {
    trailAtom = (TERM)array_GetElement(instances, j);
    subst_ContextStackPush(Ntwfo->subststate);
    if (!subst_TermUnifyIdenticalVarsNoTypesStack(Ntwfo->subststate, Ntwfo->termstate, Ntwfo->symbstate, sharedVersion, trailAtom, FALSE)) {
      subst_ContextStackPop(Ntwfo->subststate);
      continue;
#ifdef SPASS_CHECK
      misc_StartErrorReport();
      misc_ErrorReport("Something went wrong with the DISTRN\n");
      misc_FinishErrorReport();
#endif
    }
    if (ntwfo_CheckClause(Ntwfo, Trail, Clause, I+1, Prop, TrueOnPropagation, Trailsize)) {
      array_Delete(Ntwfo->mem, instances);
      return TRUE;
    }
    subst_ContextStackPop(Ntwfo->subststate);
  }
  array_Delete(Ntwfo->mem, instances);
  if (Prop == clause_GetFolLiterals(Clause)) {
    return ntwfo_CheckClause(Ntwfo, Trail, Clause, I+1, I, TrueOnPropagation, Trailsize);
  }
  if ((Prop < clause_GetPremiseLiterals(Clause)) != (I < clause_GetPremiseLiterals(Clause))) return FALSE;
  subst_ContextStackPush(Ntwfo->subststate);
  if (!subst_TermUnifyIdenticalVarsNoTypesStack(Ntwfo->subststate, Ntwfo->termstate, Ntwfo->symbstate, clause_GetAtom(Clause, Prop), clause_GetAtom(Clause, I), TRUE)) {
    subst_ContextStackPop(Ntwfo->subststate);
    return FALSE;
  }
  if (ntwfo_CheckClause(Ntwfo, Trail, Clause, I+1, Prop, TrueOnPropagation, Trailsize)) return TRUE;
  subst_ContextStackPop(Ntwfo->subststate);
  return FALSE;
}
NTWFO ntwfo_Create(MEMORY Mem, SUBSTSTATE Subststate, TERMSTATE Termstate, SYMBSTATE Symbstate, SHARER Sharer, ARRAY Clauses, DISTRN Posclauselits, DISTRN Negclauselits)
{
  unsigned i;
  NTWFO ntwfo;
  CLAUSE cur;
  SUBST tmp;
  ntwfo = memory_Malloc(Mem, sizeof(struct NTWFO_HELP));
  ntwfo->mem = Mem;
  ntwfo->subststate = Subststate;
  ntwfo->termstate = Termstate;
  ntwfo->symbstate = Symbstate;
  ntwfo->sharer = Sharer;
  ntwfo->posclauselits = Posclauselits;
  ntwfo->negclauselits = Negclauselits;
  ntwfo->postraillits = distrn_Create(Mem);
  ntwfo->negtraillits = distrn_Create(Mem);
  ntwfo->prlits = prlits_Create(Mem);
  ntwfo->tmpPropagations = array_Create(Mem, 3);
  ntwfo->substsToDelete = array_Create(Mem, 3);
  for (i = 0; i < array_GetSize(Clauses); i++) {
    cur = (CLAUSE)array_GetElement(Clauses, i);
    tmp = ntwfo_GenerateUnit(ntwfo, cur);
    if (tmp == NULL) continue;
    prlits_AddIfNotMember(ntwfo->prlits, ntwfo->sharer, ntwfo->termstate, ntwfo->subststate, cur, tmp, 0, 0);
    ntwfo->substsToDelete = array_Add(Mem, ntwfo->substsToDelete, (intptr_t)tmp);
  }
  return ntwfo;
}
void ntwfo_Delete(NTWFO Ntwfo)
{
  unsigned i;
  MEMORY mem;
  mem = Ntwfo->mem;
  distrn_Delete(mem, Ntwfo->postraillits);
  distrn_Delete(mem, Ntwfo->negtraillits);
  prlits_Delete(Ntwfo->prlits);
  array_Delete(mem, Ntwfo->tmpPropagations);
  for (i = 0; i < array_GetSize(Ntwfo->substsToDelete); i++) {
    subst_Delete(mem, (SUBST)array_GetElement(Ntwfo->substsToDelete, i));
  }
  array_Delete(mem, Ntwfo->substsToDelete);
  memory_Free(mem, Ntwfo, sizeof(struct NTWFO_HELP));
}
PRLITS ntwfo_GetPrlits(NTWFO Ntwfo)
{
  return Ntwfo->prlits;
}
BOOL ntwfo_NewLiteralOnTrail(NTWFO Ntwfo, TRAIL Trail)
{
  unsigned i, idx;
  BOOL positive;
  TERM newAtom;
  ARRAY generalizations;
  CLAUSE cur;
  NTWFO_PROPAGATION prop;
  newAtom = trail_GetAtomFromTrailPos(Trail, trail_GetSize(Trail) - 1);
  positive = trail_IsPositiveFromTrailPos(Trail, trail_GetSize(Trail) - 1);
  if (positive) {
    distrn_Insert(Ntwfo->mem, Ntwfo->postraillits, Ntwfo->termstate, newAtom, NULL, (intptr_t)newAtom);
  } else {
    distrn_Insert(Ntwfo->mem, Ntwfo->negtraillits, Ntwfo->termstate, newAtom, NULL, (intptr_t)newAtom);
  }
  generalizations = array_Create(Ntwfo->mem, 3);
  if (positive) {
    distrn_SearchGeneralizations(Ntwfo->mem, Ntwfo->negclauselits, Ntwfo->termstate, newAtom, &generalizations);
  } else {
    distrn_SearchGeneralizations(Ntwfo->mem, Ntwfo->posclauselits, Ntwfo->termstate, newAtom, &generalizations);
  }
  for (i = 0; i < array_GetSize(generalizations); i++) {
    cur = (CLAUSE)array_PairFirst((ARRAY)array_GetElement(generalizations, i));
    idx = array_PairSecond((ARRAY)array_GetElement(generalizations, i));
    subst_ContextStart(Ntwfo->subststate, Ntwfo->symbstate);
    subst_ContextStackStart(Ntwfo->subststate);
    if (!subst_TermUnifyIdenticalVarsNoTypesStack(Ntwfo->subststate, Ntwfo->termstate, Ntwfo->symbstate, clause_GetAtom(cur, idx), newAtom, FALSE)) {
      subst_ContextStackStop(Ntwfo->subststate);
      subst_ContextStop(Ntwfo->subststate);
      continue;
#ifdef SPASS_CHECK
      misc_StartErrorReport();
      misc_ErrorReport("Something went wrong with the DISTRN\n");
      misc_FinishErrorReport();
#endif
    }
    if (ntwfo_CheckClause(Ntwfo, Trail, cur, 0, clause_GetFolLiterals(cur), FALSE, trail_GetSize(Trail))) {
      subst_ContextStackStop(Ntwfo->subststate);
      subst_ContextStop(Ntwfo->subststate);
      array_Delete(Ntwfo->mem, generalizations);
      ntwfo_DeleteTmpPropagations(Ntwfo);
      return TRUE;
    }
    subst_ContextStackStop(Ntwfo->subststate);
    subst_ContextStop(Ntwfo->subststate);
  }
  array_Delete(Ntwfo->mem, generalizations);
  for (i = 0; i < array_GetSize(Ntwfo->tmpPropagations); i++) {
    prop = (NTWFO_PROPAGATION)array_GetElement(Ntwfo->tmpPropagations, i);
    prlits_AddIfNotMember(Ntwfo->prlits, Ntwfo->sharer, Ntwfo->termstate, Ntwfo->subststate, prop->clause, prop->subst, prop->idx, prop->trailsize);
  }
  ntwfo_DeleteTmpPropagations(Ntwfo);
  return FALSE;
}
unsigned ntwfo_ComputeBacktrackLevelLearnNewClause(NTWFO Ntwfo, TRAIL Trail, CLAUSE Clause)
{
  unsigned i, result;
  BOOL positive;
  TERM atom;
  SUBST tmp;
  NTWFO_PROPAGATION prop;
  tmp = ntwfo_GenerateUnit(Ntwfo, Clause);
  if (tmp) {
    prlits_RemoveUntilTrailsize(Ntwfo->prlits, Ntwfo->termstate, 0);
    prlits_AddIfNotMember(Ntwfo->prlits, Ntwfo->sharer, Ntwfo->termstate, Ntwfo->subststate, Clause, tmp, 0, 0);
    Ntwfo->substsToDelete = array_Add(Ntwfo->mem, Ntwfo->substsToDelete, (intptr_t)tmp);
    distrn_Delete(Ntwfo->mem, Ntwfo->postraillits);
    distrn_Delete(Ntwfo->mem, Ntwfo->negtraillits);
    Ntwfo->postraillits = distrn_Create(Ntwfo->mem);
    Ntwfo->negtraillits = distrn_Create(Ntwfo->mem);
    return 0;
  }
  distrn_Delete(Ntwfo->mem, Ntwfo->postraillits);
  distrn_Delete(Ntwfo->mem, Ntwfo->negtraillits);
  Ntwfo->postraillits = distrn_Create(Ntwfo->mem);
  Ntwfo->negtraillits = distrn_Create(Ntwfo->mem);
  for (i = 0; i < trail_GetSize(Trail); i++) {
    atom = trail_GetAtomFromTrailPos(Trail, i);
    positive = trail_IsPositiveFromTrailPos(Trail, i);
    if (positive) {
      distrn_Insert(Ntwfo->mem, Ntwfo->postraillits, Ntwfo->termstate, atom, NULL, (intptr_t)atom);
    } else {
      distrn_Insert(Ntwfo->mem, Ntwfo->negtraillits, Ntwfo->termstate, atom, NULL, (intptr_t)atom);
    }
    subst_ContextStart(Ntwfo->subststate, Ntwfo->symbstate);
    subst_ContextStackStart(Ntwfo->subststate);
    if (ntwfo_CheckClause(Ntwfo, Trail, Clause, 0, clause_GetFolLiterals(Clause), TRUE, i + 1)) {
      subst_ContextStackStop(Ntwfo->subststate);
      subst_ContextStop(Ntwfo->subststate);
      break;
    }
    subst_ContextStackStop(Ntwfo->subststate);
    subst_ContextStop(Ntwfo->subststate);
  }
  result = i + 1;
  prlits_RemoveUntilTrailsize(Ntwfo->prlits, Ntwfo->termstate, result);
  subst_ContextStart(Ntwfo->subststate, Ntwfo->symbstate);
  subst_ContextStackStart(Ntwfo->subststate);
  if (ntwfo_CheckClause(Ntwfo, Trail, Clause, 0, clause_GetFolLiterals(Clause), FALSE, result)) {
#ifdef SPASS_CHECK
    misc_StartErrorReport();
    misc_ErrorReport("Conflict at backtracking point\n");
    misc_FinishErrorReport();
#endif
  }
  subst_ContextStackStop(Ntwfo->subststate);
  subst_ContextStop(Ntwfo->subststate);
  for (i = 0; i < array_GetSize(Ntwfo->tmpPropagations); i++) {
    prop = (NTWFO_PROPAGATION)array_GetElement(Ntwfo->tmpPropagations, i);
    prlits_AddIfNotMember(Ntwfo->prlits, Ntwfo->sharer, Ntwfo->termstate, Ntwfo->subststate, prop->clause, prop->subst, prop->idx, prop->trailsize);
  }
  ntwfo_DeleteTmpPropagations(Ntwfo);
  return result;
}
void ntwfo_Backtrack(NTWFO Ntwfo, TRAIL Trail)
{
  unsigned i;
  BOOL positive;
  TERM atom;
  prlits_RemoveUntilTrailsize(Ntwfo->prlits, Ntwfo->termstate, trail_GetSize(Trail));
  distrn_Delete(Ntwfo->mem, Ntwfo->postraillits);
  distrn_Delete(Ntwfo->mem, Ntwfo->negtraillits);
  Ntwfo->postraillits = distrn_Create(Ntwfo->mem);
  Ntwfo->negtraillits = distrn_Create(Ntwfo->mem);
  for (i = 0; i < trail_GetSize(Trail); i++) {
    atom = trail_GetAtomFromTrailPos(Trail, i);
    positive = trail_IsPositiveFromTrailPos(Trail, i);
    if (positive) {
      distrn_Insert(Ntwfo->mem, Ntwfo->postraillits, Ntwfo->termstate, atom, NULL, (intptr_t)atom);
    } else {
      distrn_Insert(Ntwfo->mem, Ntwfo->negtraillits, Ntwfo->termstate, atom, NULL, (intptr_t)atom);
    }
  }
}
void ntwfo_ClearStackDeletedUnits(NTWFO Ntwfo)
{
  PRLITS_ANNO_LIT cur;
  ARRAY stack;
  PRLITS plits;
  unsigned i,j;
  plits = Ntwfo->prlits;
  stack = prlits_GetStack(plits);
  for (i=0, j=0; i< array_GetSize(stack); i++) {
    cur = (PRLITS_ANNO_LIT)stack[i];
    if (clause_IsMarkedDelete(prlits_GetAnnoLitOriginClause(cur))) {
      prlits_SetLitsmap(plits, ohash_Remove(prlits_GetLitsmap(plits), (OHASH_KEY_TYPE)cur, NULL, (OHASH_DELETE_DATA_FCT)prlits_HashDataDelete));
    }
    else {
      stack[j] = stack[i];
      j++;
    }
  }
  array_SetSize(stack,j);
}
