/****
  Copyright © Siemens Dematic 2001
  Version: @(#)[file] [enviro D1ent]-[version] [crtime]
  Author:	F.Drachenfels, RC D1
  Synopsis:	Image Processing InterFace: Implementation of RiDbi 
                (Region Interpretation's Data Base Interface) for SMART.
  Description:	This module contains all functions XAI requires to obtain
                information about texts, e.g. segmentation-graphs, 
		character-classification results, etc. It is an implementation
		of the interface defined in exp_ri_dbif_func.h.
		XAI is never allowed to use these functions directly but 
		only by calling the wrappers in ri_dbif. This is enforced
		by declaring ALL functions in this module to be of module
		(static) scope and exporting them solely to the ice_link'er.
  Date	Author	Modifications
   7.08.2001    init
  29.11.2001    U. Nootbaar: new sex_scr_result interface applied
   6.12.2001    implement the functions isScriptList, getRegionText, 
                AgToTextGraph, isGap, isString 
  07.01.2002    U. Nootbaar: new sex_scr_alphabet interface applied,
                             function ipif_isGap removed,
			     edgeFunc sets sex_scr_alphabet as universalist


Attention: - error_prob not used for classification; error_prob is always set 
             to 1.0!
           - make an odl-file for miscGraphDataT; now it is very bad 
             implemented 
           - functions: getRegionFontStyles,
                        isScriptList not implemented
           - function getSegmentData is very bad!!!!! (compatibility to
                        RC1000 used in hmpc). For this we need also
                        the function ipif_SegmentatorList2UINT32 (complete
                        init of nominal_threshold.tcl)
****/


/*------------------------------------------------------------- include files */
#include "ipif_obj.h"
#include "sti_ipif_base.h"

#include <string.h>
#include "Csa.h"

#include "sex_text_seg.h"
#include "sex_text.h"
#include "sex_decoder.h"

#include "sex_SegPoint.h"
#include "sex_SegPointIterator.h"
#include "sex_SegSegment.h"
#include "sex_SegSegmentAtt.h"

#include "sex_scr.h"
#include "sex_scr_result.h"

#include "ri_dbif_types.h"  
#include "ri_dbif.h"
#include "ai_cg_services.h"

#include "ice_free.h"
#include "ice_pet.h"
#include "ice_link.h"
#include "ice_collect.h"

#include "ai_print_prot.h"
#include "ai_graph.h"
#include "ai_info.h"
#include "exp_ri_dbif_type.h"

/*----------------------------------------------------------------- constants */
/*--------------------------------------------------------------- definitions */

#define UNSET -1
#define MAX_CLA_RESULT_LIST 100

/*---------------------------------------------------------- type definitions */

typedef struct {
    Graph            *cg;
    int              *mapping;
    int              *curr_line_no;
    int              number_of_nodes;
} miscGraphDataT;


typedef struct {
    Edge      e;
    char_info i;
} EdgeAndCharInfoT;

typedef struct {
  Graph    *cg;
  IceMark  *mark;
} aigFreeT;




/*-------------------------------------------------------------------- macros */

/*------------------------------------------------------- function prototypes */
static int getSegmentationGraph(const sex_text *seg_g, Graph *cg);
static void edgeFunc(const CsaEdge *csa_edge, CsaObject *clientData);
static db_getClassificationFT ipif_getClassification;
static void getSegmentFontSyles(const sex_scr *scr, int *nStyles,
                                FontStyleT **Styles);
static void aig_free(aigFreeT *aigfree);
static char* PrintEdgeLength(char* buffer, Edge* edge);
static void MarkCharEdges(char* pos, Edge* edge, va_list ap);
static void mark_node(char *pos,Vertex* node,va_list ap);

/*------------------------------------------------------ variable definitions */


/*++++
  Function:	ipif_getSegmentationGraph
  Synopsis:	This function creates an ai graph 
                from the smart graph. The function uses
                a smart segmentation server which must be
                initilialized already with the right
                configuration.
  Description:	The segmentation graph constists of
                nodes and edges (= characters, gaps and line ends).
                The segmentation graph contains no classification
                results.
                Attention: in front of each line end edge a gap
                           edge is inserted without a scr server!
  Input:	reg                - region type pointer
                LineDemand         - demanded attributes (not used)
                SegmentDemand      - demanded attributes (not used)
  Output:	SegmG              - Charactergraph
  Implicit Input:
  Implicit Output: 
  Return:		1  -  success
			0  -  no fatal error but graph is empty
  Errors/Exceptions:	< 0
++++*/ 

static int ipif_getSegmentationGraph
(
       RegionT                  *reg,
 const LineDemandT        *const LineDemand,     /* not used */
 const SegmentDemandT     *const SegmentDemand,  /* not used */
       Graph                   **SegmG
)
{
  sex_text_seg            *seg_server    = (sex_text_seg*)(reg->db);
  const sex_text          *seg_g         = NULL;  /* smart graph */
  int                      err = 0;

  (void)LineDemand;
  (void)SegmentDemand;
  
  /*-------------------------------------------------- first: ai graph create */
  TCALLOC(*SegmG, Graph, 1);
  GRAPH_QUALIFIER(*SegmG) = CHAR_EDGE_LIST;
  GRAPH_STATUS(*SegmG)    = DIRTY_TOP_SORTED | DIRTY_NON_TRIVIAL;

  /*--------------------------------------- segmentation get the smart graph */
  TRY {
    seg_g = sex_text_seg_text_result(seg_server);
  } CATCHDEFAULT {
    err = 1;
  } TRYEND;
  if (err != 0 || seg_g == NULL) { 
     TRACE_FLAG(TRACE_IPIF)
       printf("ipif_getSegmentationGraph: Created an empty graph \n");
     memset(*SegmG, 0, sizeof(Graph));
     GRAPH_QUALIFIER(*SegmG) = CHAR_EDGE_LIST;
     GRAPH_STATUS(*SegmG)    = DIRTY_NON_TRIVIAL;
     return -1;
  }

  IF_IS_TRACE(TRACE_IPIF_SEXTEXT2FILE) {
    char* filename;
    ICE_CALLOC(filename, char, strlen(reg->name)+5);
    sprintf(filename, "%s.vcg", reg->name);
    sex_text_print4xvcg(seg_g, filename);
    ICE_FREE(filename);
  }
  CHECK_N(getSegmentationGraph, (seg_g, *SegmG), 1);

  return NODE_SET(*SegmG);
}

/*++++
  Function:	getSegmentationGraph
  Synopsis:	This function creates an ai graph 
                from the smart graph. The function uses
                a smart segmentation server which must be
                initilialized already with the right
                configuration.
  Description:	The segmentation graph constists of
                nodes and edges (= characters, gaps and line ends).
                The segmentation graph contains no classification
                results.
                Attention: in front of each line end edge a gap
                           edge is inserted without a scr server!
  Input:	seg_g              - a smart text graph
  Output:	SegmG              - Charactergraph
  Implicit Input:
  Implicit Output: 
  Return:		1  -  success
			0  -  no fatal error but graph is empty
  Errors/Exceptions:	< 0
++++*/ 

static int getSegmentationGraph
(
 const sex_text                 *seg_g,
       Graph                    *cg
)
{
  int                     *mapping       = NULL;
  int                     *curr_line_no  = NULL;
  int                      node_nr       = 0; 
  int                      tot_node_nr   = 0;
  int                      prevGraphSize = 0;
  miscGraphDataT           my_data;
  const sex_SegPoint      *smart_start   = NULL;
  IceMark                 *mark1         = NULL;
  IceMark                 *mark2         = NULL;
  IceMark                 *mark3         = NULL;
  aigFreeT  	           aigfree;        /* help struct for exception */
  int                      node_index;
  
  enum {
      GETSEGMGRAPH_FATAL = 1,
      GETSEGMGRAPH_REJECT
  };
  
  EXCEPTIONS {
   case GETSEGMGRAPH_REJECT:
     TRACE_FLAG(TRACE_IPIF)
       printf("ipif_getSegmentationGraph: Created an empty graph \n");
     memset(cg, 0, sizeof(Graph));
     GRAPH_QUALIFIER(cg) = CHAR_EDGE_LIST;
     GRAPH_STATUS(cg)    = DIRTY_NON_TRIVIAL;
     ice_tfree(mark1);
     return 0;
   case GETSEGMGRAPH_FATAL:
     TRACE_FLAG(TRACE_IPIF)
       printf("ipif_getSegmentationGraph: Created the empty graph\n");
     memset(cg, 0, sizeof(Graph));
     GRAPH_QUALIFIER(cg) = CHAR_EDGE_LIST;
     GRAPH_STATUS(cg)    = DIRTY_NON_TRIVIAL;
     ice_tfree(mark1);
   default:
     return -1;
  }
  
  
  ICE_MARK(mark1);

  /*------------ get the number of nodes of the segmentation graph to allocate
                                                 the vertexes of the ai graph */
  node_nr = (int)sex_text_noActiveNodes_get(seg_g);
  HANDLE_P(vertex_size, (cg, node_nr), GETSEGMGRAPH_FATAL);
  ADJACENCIES(VERTEX(0, cg)) = NULL;
  GRAPH_STATUS(cg)          &= ~DIRTY_TOP_SORTED;
  IF_IS_TRACE(TRACE_IPIF_PRINT_AIGRAPH){
    FORALL_NODES_INCREASING(node_index, cg) {
      cg->root[node_index].name=-1;
    }
  }

  /*--- allocate a mapping table for the conversion seg-node-id to ai-node-id */
  HANDLE_P(mark2 = ice_tmark, (), GETSEGMGRAPH_FATAL);
  tot_node_nr = (int)sex_text_noIndices(seg_g);
  TMALLOC(mapping, int, tot_node_nr);
  memset(mapping, UNSET, tot_node_nr * sizeof(int));
  TMALLOC(curr_line_no, int, tot_node_nr); /* note at each node the line number */
  memset(curr_line_no, UNSET, tot_node_nr * sizeof(int));
  HANDLE_P(mark3 = ice_tmark, (), GETSEGMGRAPH_FATAL);

  /*---------- traverse the smart graph and create the ai graph with the right 
                                                                   attributes */
  /* set my client data for edgeFunc */
  my_data.cg = cg;
  my_data.mapping = mapping;
  my_data.curr_line_no = curr_line_no;
  my_data.number_of_nodes=0;
  /* set the first ai-node-id */
  smart_start = (const sex_SegPoint*)sex_text_startNode(seg_g);
  my_data.mapping[sex_SegPoint_nodeIndex_get(smart_start)] = 0;
  my_data.curr_line_no[sex_SegPoint_nodeIndex_get(smart_start)] = 0;
  /* do something for exception handling */
  aigfree.cg = cg;
  aigfree.mark = mark1;
  TRY{
    ONERROR(aig_free, &aigfree);
    sex_text_workOnGraphQueued(seg_g, (CsaObject*)&my_data, OUTGOING, 
                               0, 0, edgeFunc);
  } TRYEND;
  if (NODE_SET(cg) == prevGraphSize) {
    /* Obviously nothing was added to cg */
    GOTO_EXCEPTION(GETSEGMGRAPH_REJECT);
  }

  IF_IS_TRACE(TRACE_IPIF_PRINT_AIGRAPH) {
    print_graph(cg, MarkCharEdges, mark_node, 6, FORCE_LEFT);
  }

  GRAPH_STATUS(cg) &= ~(DIRTY_WELL_FOUNDED|DIRTY_FIRST_NODE_ROOTED|
			DIRTY_ISOLATED_NODES|DIRTY_NON_TRIVIAL);
  HANDLE_P(SortTopological, (cg), GETSEGMGRAPH_REJECT);
  
  TRACE_FLAG(TRACE_DATABASE)
      cgs_traceCharacterGraph(cg, "Character Graph\n");
  
  ICE_FORGET(mark3,mark2);
  
  return 1;
}

/*++++
  Function:	edgeFunc
  Synopsis:	This function will be called from seg_text_workOnGraphQueued.
  Description:	edgeFunc is called for the edges.
                build the ai graph edge for edge
                Attention in front of line edges this function inserts
                          a dummy gap edge (without a scr server!!)
  Input:	node             - node of the smart graph
                my_data          - misc data for ai graph construction use
  Output:        
  Return:
++++*/ 

static void edgeFunc
(
  const CsaEdge			*csa_edge,
        CsaObject               *my_data
)
{
  miscGraphDataT    *my  = (miscGraphDataT*) my_data;
  int           start_id = (int)CsaNode_nodeIndex_get(CsaEdge_source_get(csa_edge));
  int           end_id   = (int)CsaNode_nodeIndex_get(CsaEdge_target_get(csa_edge));
  int           ai_start_id = my->mapping[start_id];
  const sex_SegSegmentAtt *seg_att = 
                     sex_SegSegment_attribute_get((const sex_SegSegment*)csa_edge);
  sex_scr       *scr     = sex_SegSegmentAtt_class_server_get(seg_att);
  Edge          *e;
  ObjDscT       *objdsc  = NULL;
  int            new_line = 0;
  const sex_scr_result *result = NULL;
  const sex_scr_result_el *result_el  = NULL;  /* B-nootbaar */
  unsigned                 result_len = 0;
  int                      result_el_code = 0; /* E-nootbaar */

  EXCEPTIONS {
      default:
	  THROW(CsaStorageOverflow);
  }


  /*------------------------------------- is an edge a line end edge
                            then insert a gap edge in front of this line edge */
  if (scr) {
    sex_scr_alphabet_input (scr, "\041-\176"); /* nootbaar */
    result = sex_scr_result_result(scr);
    result_len = sex_scr_result_el_len (result);               /* B-nootbaar */
    if (result_len) {
      result_el = sex_scr_result_el_get (result, 0);
      result_el_code = sex_scr_result_el_code_class_get (result_el);
    }
    if (result_len && (result_el_code == SMART_LINEFEED)) {    /* E-nootbaar */

      if (my->mapping[end_id] != UNSET) { /*edge is already visited->do nothing */
        return;
      }
      else { /* insert a gap edge in front of this line edge for aa */
        my->number_of_nodes++;
        my->curr_line_no[end_id] = my->curr_line_no[start_id]; 
        new_line = 1;
        HANDLE_P(vertex_size, (my->cg, NODE_SET(my->cg) + 1),-1);
        HANDLE_P(e = create_edge,(my->cg, ai_start_id, my->number_of_nodes),-1);
        my->cg->root[ai_start_id].name = start_id;
        my->cg->root[my->number_of_nodes].name = -1;
        start_id = -1;
        ai_start_id = my->number_of_nodes;

        /*------------------------------------------------ set the attributes */
        HTCALLOC(EDGE_INFO(e),char_info,1,-1);
	HANDLE_P(objdsc=sti_ipif_ObjDscT_create,(),-1);
        objdsc->in_line = my->curr_line_no[end_id];
	WRITE_OBJ_DSC(CHAR_INFO(e), objdsc);
        CHAR_INFO(e)->original_length = 0; /* costs */
        CHAR_INFO(e)->original_token = 0;
        CHAR_INFO(e)->segm = 0;
	TOKEN(e) = CHAR_INFO(e)->original_token;
        EDGE_LENGTH(e) = CHAR_INFO(e)->original_length; 
        INFO_QUALIFIER(CHAR_INFO(e)) = CHAR_EDGE_LIST;
      }
    }
  }

  /*---------------------------------------- get the ai-node-id for this node */
  if (my->mapping[end_id] == UNSET) { /* is this smart node already visited?*/
      my->number_of_nodes++;
      my->mapping[end_id] = my->number_of_nodes;
      if (start_id != -1) my->curr_line_no[end_id] = my->curr_line_no[start_id];
  }
  /*------------------------------------------------- create/link the ai edge */
  HANDLE_P(e = create_edge,(my->cg, ai_start_id, my->mapping[end_id]),-1);
  my->cg->root[ai_start_id].name = start_id;
  my->cg->root[my->mapping[end_id]].name = end_id;

  /*------------------------------------------------------ set the attributes */
  HTCALLOC(EDGE_INFO(e),char_info,1,-1);
  HANDLE_P(objdsc=sti_ipif_ObjDscT_create,(),-1);
  WRITE_OBJ_DSC(CHAR_INFO(e), objdsc);
  CHAR_INFO(e)->original_length = 0; /* costs */
  CHAR_INFO(e)->original_token = 0;
  CHAR_INFO(e)->segm = 0;
<<<<<<< t
  objdsc->segment = seg_att;
  /*
    objdsc->region =  sex_SegSegmentAtt_?the sex_region?_get(seg_att); 
  */
  /* stuff for copy and paste
     sex_SegSegmentAtt_class_server_get(objdsc->segment)
  */
=======
  getSegmentFontSyles(sex_SegSegmentAtt_class_server_get(seg_att),
                      &(CHAR_INFO(e)->nStyle), 
                      (FontStyleT**)&(CHAR_INFO(e)->style));

  objdsc->db = (void*)sex_SegSegmentAtt_class_server_get(seg_att);
  objdsc->id = (unsigned int)sex_SegSegmentAtt_id_get(seg_att);
>>>>>>> 1.1.1.1.2.1
  objdsc->in_line = my->curr_line_no[end_id];

  TOKEN(e) = CHAR_INFO(e)->original_token;
  EDGE_LENGTH(e) = CHAR_INFO(e)->original_length; 
  INFO_QUALIFIER(CHAR_INFO(e)) = CHAR_EDGE_LIST;
<<<<<<< t
=======
  REFERENCE(e) = CHAR_INFO(e)->dasi_id;
  
  if(new_line) {
    my->curr_line_no[end_id]++; /* the current line edge belongs to
                                   the previous line number */
  }
>>>>>>> 1.1.1.1.2.1

  return;
}

/*++++
  Function:     getSegmentFontSyles
  Synopsis:     the function looks for the style of the character an fills 
                the old style array
  Input:        sex_scr          - character recognizer server
  Ountput:      nStyles          - length of the style array
                Styles           - style array
++++*/

static void getSegmentFontSyles
(
  const sex_scr     *scr, 
  int               *nStyles,
  FontStyleT       **Styles
)
{
  const sex_scr_font *scr_font = NULL;
        int           j;

  EXCEPTIONS {
      default:
	  THROW(CsaStorageOverflow);
  }

  if (scr && sex_scr_font_len(scr)) {
    j = 0;
    scr_font = sex_scr_font_get(scr, 0); /* at the moment index=0 only set */
    if (scr_font) {
      HTCALLOC((*Styles), FontStyleT, STYLE_MAX, -1);
      if (*Styles) {
        
        if (!strcmp(sex_scr_font_font_get(scr_font), "HAND")) {
          (*Styles)[j++] = STYLE_HAND;
        }
        if (!strcmp(sex_scr_font_font_get(scr_font), "POLY")) {
          (*Styles)[j++] = STYLE_VAR;
          (*Styles)[j++] = STYLE_FIX;
        }
        *nStyles = j;
      }
    }
  }
}

/*++++
  Function:	ipif_addClassifications
  Synopsis:	This function adds single character classification
                results to input (segmentation) graph.
  Description:	walks through the ai graph (segmenation graph) 
                and calls for each edge the scr server tagged on the
                edge. Each edge with more than one classifier choices 
                will be copied (number of choices time) and in parallel
                inserted.
  Input:	CharG            - segmentation Graph
		ClassifierDemand - demanded attributes
                error_prob       - requested quality of classification result
                                   (not implemented yet)
  Output:	CharG - Charactergraph, (graph with classification results)
  Implicit Input:
  Implicit Output:
  Return:		number of edges in output graph
  Errors/Exceptions:	return < 0
++++*/ 

static int ipif_addClassifications
(
       Graph                   **CharG,             
 const CharEncodingT             DefaultSegment,    /* not used */
 const ClassifierDemandT  *const ClassifierDemand,
       char                     *error_prob         /* not yet used */
)
{
  Graph                 *SegmG          = *CharG;
  Vertex                *V;
  Edge                  *s, *e, *f;
  int                    nChoices;
  ClassifierResultT      Result[MAX_CLA_RESULT_LIST];
  ClassifierResultListT  ResultList;
  EdgeAndCharInfoT      *EACI;

  (void)DefaultSegment;
  (void)error_prob;

  if (!GraphCondition(SegmG, ~(DIRTY_NON_TRIVIAL)))
    return 0;

  if (ClassifierDemand->Generic.Type != CLASSDEMAND_ALPHABET) {
    TRACE_FLAG(TRACE_ERROR)
      printf("ipif_addClassifications: only CLASSDEMAND_ALPHABET supported!\n");
    return 0;
  }

  /* Prepare ResultList. It's big enough, so there's no need for realloc
     in ipif_getClassification */
  ResultList.Space            = MAX_CLA_RESULT_LIST;
  ResultList.ClassifierResult = Result;

  /* traverse the ai graph and call the classifier */
  FORALL_VERTICES_INCREASING(V, SegmG) {
    for (s = ADJACENCIES(V); s; ) {
      e = s;       /* process current edge */
      s = s->next; /* save next edge, so new edges can be inserted before s */

      ResultList.nChoices = 0;
      TRY {
        REPORT(nChoices = ipif_getClassification,
	       (READ_OBJ_DSC(CHAR_INFO(e)), ClassifierDemand,
	        error_prob, &ResultList));
      } CATCHDEFAULT {
        TRACE_FLAG(TRACE_ERROR)
          printf("ipif_addClassifications: fatal error occurred in getClassification!\n");
        return 0;   
      }TRYEND;
      if (nChoices < 1) { /* never happens */
        TRACE_FLAG(TRACE_ERROR)
	  printf ("ipif_addClassification: get no classification result\n");
      }
      else {
        int c = 1;

        TOKEN(e)                      = Result[0].Choice;
        EDGE_LENGTH(e)                = Result[0].Length;
        /* CHAR_INFO(e)->classifier      = cv[0].classifier; */
        CHAR_INFO(e)->original_length = EDGE_LENGTH(e);
	CHAR_INFO(e)->original_token  = TOKEN(e);
	e->edit_stack                 = NULL;
	EDIT_OPERATOR(e)              = (edit_operation)0;

	if (nChoices > 1) {
	  TMALLOC(EACI, EdgeAndCharInfoT, nChoices);
	    
	  for (; c < nChoices; c++, EACI++) {
	    f = e->next                   = &(EACI->e);
	    /* set all elements of Edge (non-initialized memory) */
	    TARGET_NODE(f)                = TARGET_NODE(e);
	    EDGE_ID(f)                    = EDGE_SET(SegmG)++;
	    EDGE_INFO(f)                  = &(EACI->i);
	    f->edit_stack                 = NULL;
	    EDIT_OPERATOR(f)              = (edit_operation)0;
	    EDGE_LENGTH(f)                = Result[c].Length;
	    TOKEN(f)                      = Result[c].Choice;
	    REFERENCE(f)                  = 0;
	    memcpy(EDGE_INFO(f), EDGE_INFO(e), sizeof(char_info));
	    CHAR_INFO(f)->original_length = EDGE_LENGTH(f);
	    CHAR_INFO(f)->original_token  = TOKEN(f);
	    e = f;
	  }
	  e->next = s; /* don't forget successor edge */
        }/* endif(nChoices > 1) */
      }/* endelse(nChoices >= 1) */
    }/* endfor(ALL_EDGES s) */
  }/* endfor(ALL_VERTICES V) */

  *CharG = SegmG;

  TRACE_FLAG(TRACE_DATABASE)
    cgs_traceCharacterGraph(*CharG, "\n\nClassification graph:\n");
  
  return EDGE_SET(*CharG);
}

/*++++
  Function:	ipif_getClassification
  Synopsis:	returns the classification result(s) for the given edge
  Description:	calls the scr server belonging to the current edge with
                with the input alphabet
  Input:	objdcs           - ObjDscT pointer
		ClassifierDemand - only the access ByAlphabet is supported
                error_prob       - requested quality of classification result
  Output:	Result - list of choices. To save time, this
			 buffer can be allocated by the caller.
			 If it is too small, new memory is
			 allocated!
  Implicit Input:
  Implicit Output:
  Return:		number of choices found
  Errors/Exceptions:	return < 0
++++*/ 

static int ipif_getClassification
(
       ObjDscT                      *objdsc,
 const ClassifierDemandT      *const ClassifierDemand,
       char                         *error_prob, /*not yet used; always set->1*/
       ClassifierResultListT        *Result
)
{
  const sex_scr_result    *result = NULL; 
  const sex_scr_result_el *result_el  = NULL;  /* B-nootbaar */
  unsigned                 result_len = 0;     /* E-nootbaar */
  int                      i;
  int                      q; /* quality */
  CharEncodingT            c; /* shape */
  ClassifierResultT        tempResult[MAX_CLA_RESULT_LIST];
  char                    *Alphabet = ClassifierDemand->Generic.Alphabet;
  const int                maxChoices = ClassifierDemand->Generic.maxChoices;
  const int                maxProb = /* is this feature used from anybody */
    MAX(0, MIN(255, (255 - ClassifierDemand->Generic.maxLength)));
  (void) error_prob;
  if (ClassifierDemand->Generic.Type != CLASSDEMAND_ALPHABET) {
    TRACE_FLAG(TRACE_ERROR)
      printf("ipif_getClassifications: only CLASSDEMAND_ALPHABET supported!\n");
    return 0;
  }

  if (!Result) {
    TMALLOC(Result, ClassifierResultListT, 1);
    Result->nChoices = Result->Space = 0;
  }

  if (objdsc->segment == NULL) { 
    /*no segments exists -> current edge is a gap edge inserted from me ;-) 
      remember, this one in front of the line edges */
    tempResult[Result->nChoices].Length   = 0;
    tempResult[Result->nChoices].Choice   = ' ';
    tempResult[Result->nChoices].Alphabet = " ";
    tempResult[Result->nChoices].Style   = (CharStyleT)0;
    (Result->nChoices)++;
  }
  else {
<<<<<<< t
    sex_scr *scr = sex_SegSegmentAtt_class_server_get(objdsc->segment);
=======
    sex_scr_alphabet_input (scr, Alphabet); /* nootbaar */
#if 0
>>>>>>> 1.1.1.1.2.1
    int alphabet_len = strlen(Alphabet);
    sex_scr_alphabet_resize(scr,0);
    for (k = 0; k < alphabet_len; k++) { 
      if (Alphabet[k] == '\\') continue;
         sex_scr_alphabet_input (scr, Alphabet[k], k); 
    }
#endif

    /*--------------------------------------------- get classification result */
    sex_scr_error_prob_input(scr, 1.0); /* error probe set to 1 !!! */
    result = sex_scr_result_result(scr);
    /* through all choices (== shapes) */
    result_len = sex_scr_result_el_len (result);               /* B-nootbaar */
    for (i = 0; i < (int)result_len && i < maxChoices; i++) {
      result_el = sex_scr_result_el_get (result, i);
      c = (CharEncodingT)sex_scr_result_el_code_class_get(result_el); /*choice*/
                                                               /* E-nootbaar */
#ifndef NDEBUG
      if (Alphabet[0]!='.' && !strchr(Alphabet, (int)c) && (char)c != ' ' &&
	  c != SMART_SEG_REJECT) {
	  char cc = (char)c;;
	  TRACE_FLAG(TRACE_ERROR) {
	      printf("character '%c' not in output alphabet \"%s\"\n",cc,Alphabet);
	  }
	  continue; /* return(-1); */
      }
#endif
      q = (int)(sex_scr_result_el_prob_get (result_el) * 255);   /* quality; nootbaar */
      if (q <= maxProb) continue; /* I don't think this is very useful */
      if ((q = (255 - q)) < 0) {                          /* quality -> costs */
	  TRACE_FLAG(TRACE_FATAL) {
          printf("scr: Character probability out of range: "
    	         "Choice: %d  Char: %c  Prob: %d\n",
	  	 (int)i, (char)c, q);
	  }
	  return -1; 
      }
      if (Result->nChoices < MAX_CLA_RESULT_LIST) {
        tempResult[Result->nChoices].Length   = q;
        tempResult[Result->nChoices].Choice   = c;
        tempResult[Result->nChoices].Alphabet = Alphabet;
        tempResult[Result->nChoices].Style   = (CharStyleT)0;
        (Result->nChoices)++;
      }
    } /* shape_len */
    if (Result->nChoices == 0) {
      /* set classifier reject */ 
      tempResult[Result->nChoices].Length   = 0;
      tempResult[Result->nChoices].Choice   = '^';
      tempResult[Result->nChoices].Alphabet = "^";
      tempResult[Result->nChoices].Style   = (CharStyleT)0;
      (Result->nChoices)++;
    }
  } /* a valid scr server exists */

  if (Result->nChoices > 0) {
    /* Allocate memory for list of results if necessary */
    if (Result->Space < Result->nChoices) {
      TMALLOC(Result->ClassifierResult, ClassifierResultT,
	      Result->nChoices);
    }
    memcpy(Result->ClassifierResult, tempResult,
	   Result->nChoices * sizeof(ClassifierResultT));
  }

  return Result->nChoices;
}

/*++++
  Function:	ipif_getSegmentData
  Synopsis:	Gets relevant data about the segmentation of
                the current edge
  Description:  Attention: very bad implemented. The segmentator
                           is guessed from the font style! This
                           function will be removed in the future
  Input:	objdsc      - ObjDscT pointer
		Orientation -  Left or right context or both
				(for Segmentators of O_GAPs only)
  Output:	Segmentator - always set to 0
		Cut         - always set to 0
  Implicit Input:
  Implicit Output:
  Return:		0x0  -  No data available
			0x1  -  Request for Segmentator served
			0x2  -  Request for Cut served
  Errors/Exceptions:	return < 0
++++*/ 

static int ipif_getSegmentData
(
       ObjDscT            *objdsc,
 const OrientationT        Orientation, /* not used */
       UINT32       *const Segmentator,
       int          *const Cut 
)
{
  int                    ret_val = 0;
  const sex_scr_font    *scr_font = NULL;
  const sex_scr         *scr;
  (void)Orientation;

  if (Cut) { /* not implemented */
      *Cut = 0;
      ret_val += 2;
  }
  if (Segmentator) { /* QaD !! */
    *Segmentator = 1;   /* Segmentator FIX is default !! */
    ret_val += 1;
    if (objdsc->region){
      TRY {
	scr=sex_SegSegmentAtt_class_server_get(objdsc->segment);
	if (sex_scr_font_len (scr)) {
	  /* is not a sti dummy character  */
	  scr_font = sex_scr_font_get (scr, 0); 
	  /* at the moment index=0 only set */
	  if (!strcmp(sex_scr_font_font_get(scr_font), "HAND")) {
	    *Segmentator = 2;   /* Segmentator UNIH very bad !! */
	  }
	}
      } CATCHDEFAULT {
	MSGPRINT(stdout);
	return -1;   
      } TRYEND;
    }
  }
  return ret_val;
} /* end ipif_getSegmentData */


/*++++
  Function:          ipif_SegmentatorList2UINT32
  Synopsis:          Convert a list of segmentator names
  Description:       should be deleted as soon as possible
  Input:             lsit     - list of segmentator names
                     len      - list length
  Output:            res      - bit mask
  Implicit Input:
  Implicit Output:
  Return:            0
  Errors/Exceptions: < 0
++++*/

static int ipif_SegmentatorList2UINT32
(
 char      **list,
 int         len,
 UINT32      *const res
)
{
  int    i;
  int    code;
 
  for (i=0, *res=0; i<len; i++) {
    code = 0;
    if (!strcmp(list[i], "FIX")) code = 1;
    if (!strcmp(list[i], "VAR")) code = 1;
    if (!strcmp(list[i], "HAND")) code = 2;
    if (!strcmp(list[i], "ZIP1")) code = 2;
    if (!strcmp(list[i], "ZIP2")) code = 2;
    if (!strcmp(list[i], "ZIP3")) code = 2;
    if (!strcmp(list[i], "NUM1")) code = 2;
    if (!strcmp(list[i], "NUM2")) code = 2;
    if (!strcmp(list[i], "NUM3")) code = 2;
    if (!strcmp(list[i], "POBX")) code = 2;
    if (!strcmp(list[i], "BXNR")) code = 2;
    if (!strcmp(list[i], "STATE1")) code = 2;
    if (!strcmp(list[i], "STATE2")) code = 2;
    if (!strcmp(list[i], "STATE3")) code = 2;
    if (!strcmp(list[i], "BORDERED_PC_M")) code = 1;
    if (!strcmp(list[i], "BORDERED_PC_H")) code = 2;
    if (!strcmp(list[i], "NEW")) code = 2;
    *res |= code;
  }
  return 0;
}

/*++++
  Function:          ipif_getRegionText
  Synopsis:          build an ai graph out of barcode result
  Description:       see above
  Input:             region   - a region pointer
  Output:            text     - container for the text data
  Return:            0
  Errors/Exceptions: return < 0
++++*/
static int ipif_getRegionText(RegionT *const region, Graph **const text)
{
  sex_decoder             *decoder       = (sex_decoder*)(region->db);
  const sex_text          *seg_g         = NULL;  /* smart graph */
  Graph                   *SegmG         = NULL;  /* ai graph */
  ClassifierDemandT        ClassifierDemand;
  int                      err = 0;

  /*-------------------------------------------------- first: ai graph create */
  TCALLOC(SegmG, Graph, 1);
  GRAPH_QUALIFIER(SegmG) = CHAR_EDGE_LIST;
  GRAPH_STATUS(SegmG)    = DIRTY_TOP_SORTED | DIRTY_NON_TRIVIAL;

  /*----------------------------------------------------- get the smart graph */
  TRY {
    seg_g = sex_decoder_text_result(decoder);
  } CATCHDEFAULT {
    err = 1;
  } TRYEND;
  if (err != 0 || seg_g == NULL) { 
     TRACE_FLAG(TRACE_IPIF)
       printf("ipif_getRegionText: Created an empty graph \n");
     memset(SegmG, 0, sizeof(Graph));
     GRAPH_QUALIFIER(SegmG) = CHAR_EDGE_LIST;
     GRAPH_STATUS(SegmG)    = DIRTY_NON_TRIVIAL;
     return -1;
  }
  CHECK_N(getSegmentationGraph, (seg_g, SegmG), 1);
  TRACE_FLAG(TRACE_IPIF)
    printf("ipif_getRegionText: an ai graph is created from barcode string\n");
  memset(&ClassifierDemand, 0, sizeof(ClassifierDemandT));
  ClassifierDemand.Generic.Type = CLASSDEMAND_ALPHABET;
  ClassifierDemand.Generic.Alphabet = ".";
  ClassifierDemand.Generic.maxChoices = 10;
  ClassifierDemand.Generic.maxLength = 255;
  CHECK(ipif_addClassifications, (&SegmG, 0, &ClassifierDemand, "high"));

  *text = SegmG;
  
  return 0;
}

/*++++
  Function:     ipif_getRegionFontStyles
  Synopsis:     This function retrieves font styles (fix, var,
                hand, ...) for the given region
  Description:  not yet implemented
  Input:        reg                - RegionT pointer
  Output:       nStyles            - number of entries in Styles
                Styles             - list of styles,
                                     memory is allocated.
                mostDifficultStyle -
  Implicit Input:
  Implicit Output:
  Return:               number of different styles found
  Errors/Exceptions:    return < 0
++++*/
static int ipif_getRegionFontStyles
(
       RegionT      *reg,
       int          *const nStyles,
       FontStyleT  **const Styles,
       FontStyleT   *const mostDifficultStyle
)
{

    (void)reg;
    (void)nStyles;
    (void)Styles;
    (void) mostDifficultStyle;


  TRACE_FLAG(TRACE_ERROR)
	printf("ipif_getRegionFontStyles: not implemented\n");

  return 0;
}

/*++++
  Function:          ipif_getLineNumber
  Synopsis:          Gets the number of the line the current object
                     belongs to. Line #0 is the bottom line.
  Description:       not implemented
  Input:             charobj      - ObjDscT pointer (attention word & char ids
                                    are possible)
                     ignoreReject - not supported
  Output:            LineNumber    - of the current object
                     maxLineNumber - attention it is the current line number
				     (set because of compatibility)
  Implicit Input:
  Implicit Output:
  Return:            = 0  -  no line object found
                     > 0  -  OK
  Errors/Exceptions: return < 0
++++*/
static int ipif_getLineNumber
(
       ObjDscT             *charobj,
 const ignoreRejectT        ignoreReject, /* not supported */
       int           *const LineNumber,
       int           *const maxLineNumber /* not supported */
)
{

  (void) ignoreReject;

  if(LineNumber) {
    *LineNumber = charobj->in_line;
  }
  if(maxLineNumber) {
    *maxLineNumber =  (charobj->in_line + 1); /* not support for this implementation */
  }

  return 0;
}

<<<<<<< t
static int ipif_segmentsAreSameRegion(ObjDscT *objdsc1, ObjDscT *objdsc2, int* same)
{
  if (objdsc1->region==NULL || objdsc2->region==NULL) {
    *same = 0;
  } 
  else {
    *same = (objdsc1->region == objdsc2->region);
  }
  return(0);
}



/*++++
  Function:          ipif_isGap
  Synopsis:          looks if the given object is a gap or a character
  Description:       see above
  Input:             charobj         - ObjDscT pointer
  Output:            is_gap           - 1 == gap, 0 == no gap
  Return:            0
  Errors/Exceptions: return < 0
++++*/
static int ipif_isGap
(
  ObjDscT       *charobj,
  int           *is_gap
)
{
  const sex_scr_result    *result = NULL;
  const sex_scr_result_el *result_el = NULL;
   
  *is_gap = 0;

  BEGIN {
    if (charobj->region) {  /* is not a sti dummy character  */
      sex_scr *scr;
      scr = sex_SegSegmentAtt_class_server_get(charobj->segment);
      sex_scr_alphabet_resize(scr, 0);
      sex_scr_alphabet_input (scr, ' ', 0); 
      result = sex_scr_result_result(scr);
      if (sex_scr_result_el_len(result) > 0) {
	result_el = sex_scr_result_el_get (result, 0);
        if (sex_scr_result_el_code_class_get(result_el) == SMART_WORDGAP) {
          *is_gap = 1;
        }
      }
    }
  } END;

  return 0;
}
=======
>>>>>>> 1.1.1.1.2.1

/*++++
  Function:          ipif_AgToTextGraph
  Synopsis:          convert a part (from, to) of the ai graph to a smart
                     text seg graph
  Description:       see above
  Input:             *reg      region description pointer
		     *ag       ai graph
                     from_node begin of the graph interval
                     to_node   end of the graph interval
  Output:            **sg      smart graph of the given ai graph interval  
  Return:            0
  Errors/Exceptions: return < 0
++++*/
 
int ipif_AgToTextGraph
(
  Graph      *ag,        
  int	      from_node, 
  int         to_node,  
  sex_text  **sg    /* original sex_text pointer */
)
{
  sex_text          *isg = NULL; /* internal smart graph */
  sex_SegPoint      *from_sp = NULL, *to_sp = NULL; /* smart point */
  sex_SegPointAtt   *spa     = NULL; /* smart point attribute */
  sex_SegSegment    *se = NULL;      /* smart edge */
  sex_SegSegmentAtt *sea = NULL;     /* smart edge attribute */
  sex_SegSegmentAtt *seg_tmp;
  sex_SegPoint     **node_map_a = NULL;   /*mapping table: ai-node -> smart point*/
  sex_scr           *scr_tmp;
  Vertex            *vertex;
  Edge              *edge;
  int                from_vertex_name = 0;
  int                gap_vertex_name = -1;
  Graph             *iag = NULL;     /* address graph of the given interval */
 
  *sg = isg;
 
  /*--------------------------------------- first prepare the graph interval */
  if((iag = graph_interval (ag, from_node, to_node)) ==  NULL) {
    TRACE_FLAG(TRACE_WARNING)
  	  printf("ipif_AgToTextGraph: graph interval is empty!\n");
    return 0;
  }
  TRACE_FLAG(SCRIPT_INPUT)
    printf ("build smart text graph from ai graph interval: \n");

  /*------- next: go through the marked nodes and build the smart text graph */
  TRY {
    ONERRORDELETE(sex_text, isg); /* deletes all linked points and segments */
    ONERRORDELETE(sex_SegPointAtt, spa); /* for the not linked current point */
    ONERRORDELETE(sex_SegPoint, from_sp);
    ONERRORDELETE(sex_SegPoint, to_sp);
    ONERRORDELETE(sex_SegSegmentAtt, sea);
    ONERRORDELETE(sex_SegSegment, se);
    ONENDDELETE(void, node_map_a);
    /* allocate the node mapping table (ai graph node to smart graph point */
    node_map_a = (sex_SegPoint**) CsaCalloc(NODE_SET(iag), sizeof(sex_SegPoint*));
    /* create the smart graph and the first node */
    isg = sex_text_create ();
    spa = sex_SegPointAtt_create ();
    from_sp = sex_SegPoint_initCreate (isg, spa);
    node_map_a[0] = from_sp; /* insert the first node in the mapping table */
 
    FORALL_VERTICES_INCREASING(vertex, iag) {
      FORALL_EDGES(vertex, edge) {
        /* attention: remove ai-help-edges -> remember those line end gaps */
        if (READ_OBJ_DSC(CHAR_INFO(edge))->region == NULL) { /* ai-gap-edge */
          gap_vertex_name = NODE(vertex, iag);
        }
        else { /* no ai-gap-edge -> accept this edge */
          if (gap_vertex_name >= 0) from_vertex_name = gap_vertex_name;
          else from_vertex_name = NODE(vertex, iag);
          gap_vertex_name = -1;

          if (node_map_a[from_vertex_name]) { /* from node exists already? */
            from_sp = (sex_SegPoint*)node_map_a[from_vertex_name];
          } else {
            /* new (end)point */
            spa = sex_SegPointAtt_create ();
            from_sp = sex_SegPoint_initCreate (isg, spa);
            node_map_a[from_vertex_name] = from_sp;
          }
          if (node_map_a[TARGET_NODE(edge)]) { /* to node exists? */
            to_sp = (sex_SegPoint*)node_map_a[TARGET_NODE(edge)];
          } else {
            /* new (end)point */
            spa = sex_SegPointAtt_create ();
            to_sp = sex_SegPoint_initCreate (isg, spa);
            node_map_a[TARGET_NODE(edge)] = to_sp;
          }
          /* new edge between from_sp and to_sp */
          sea = sex_SegSegmentAtt_create();
	  seg_tmp = READ_OBJ_DSC(CHAR_INFO(edge))->segment;
	  scr_tmp = sex_SegSegmentAtt_class_server_get(seg_tmp);
          sex_SegSegmentAtt_class_server_set(sea, scr_tmp);
          se=sex_SegSegment_initCreate(from_sp, to_sp, sea);
          TRACE_FLAG(TRACE_TEXTGRAPH) {
            printf ("edge from %d to %d\n",
                     (int)CsaNode_nodeIndex_get(sex_SegSegment_source_get(se)),
                     (int)CsaNode_nodeIndex_get(sex_SegSegment_target_get(se)));
          }
        }
      }
    }
  } CATCHDEFAULT {
    TRACE_FLAG(TRACE_ERROR)
  	  printf("ipif_AgToTextGraph: something happens no smart graph was built\n");
  } TRYEND;

  IF_IS_TRACE(TRACE_IPIF_SEXTEXT2FILE) {
    char* filename;
    ICE_CALLOC(filename, char, 100);
    sprintf(filename, "swr_in_%d.vcg", (int)isg);
    sex_text_print4xvcg(isg, filename);
    ICE_FREE(filename);
  }

  *sg = isg;

  return 0;

}/* end ipif_AgToTextGraph */

/*++++
  Function:          ipif_isScriptList
  Synopsis:          finds out if one of the characters in the given cloud is
                     flagged as HAND then set the is_script flag.
  Description:       see above
  Input:             NodeEdgeListLen - size of NodeEdgeList
                     NodeEdgeList    - set of syntax graph edges (cloud)
  Output:            is_script       - 1: there is a script word/character
                                       0: there's no script word
  Return:            0  - no error
  Errors/Exceptions: return < 0
++++*/
 
static int ipif_isScriptList
(
 const int         NodeEdgeListLen,
 const node_edge  *const NodeEdgeList,
       int        *const is_script
)
{
  int        i;                   /* counter through cloud's parser edge list */
  int        j;               /* counter through parser edge's character list */
  Edge*      curr_scan_edge;                       /* short for cloud element */
  scan_info* scan_edge_info;   /* short for current cloud element's edge_info */
  Edge*      curr_char_edge;              /* short for current character edge */
  const sex_scr_font *scr_font = NULL;
  const sex_scr      *scr = NULL;

  *is_script = 0;

  /* if the first hand character is found then set the script flag */
  for (i = 0; i < NodeEdgeListLen; i++) {
    if ((curr_scan_edge = NodeEdgeList[i].edge)) {
      for (scan_edge_info = SCAN_INFO(curr_scan_edge);
           scan_edge_info;
           scan_edge_info=scan_edge_info->info) {
        if (INFO_QUALIFIER(scan_edge_info) == SCAN_EDGE_LIST ) { break; }
      }
      if (!scan_edge_info) {
        TRACE_FLAG(TRACE_WARNING)
          printf("isScriptList(): scan_info not found at edge %d.\n",
                 EDGE_ID(curr_scan_edge));
        return -1;
      }
 
      for (j = 0; j < scan_edge_info->no_list_elements; j++) {
        if ((curr_char_edge = scan_edge_info->node_edge_list[j].edge)
            && EDGE_INFO(curr_char_edge)
            && *((graph_types*)EDGE_INFO(curr_char_edge)) == CHAR_EDGE_LIST) {
          if(READ_OBJ_DSC(CHAR_INFO(curr_char_edge))->region) {/* not a dummy char */
	    sex_SegSegmentAtt *seg = READ_OBJ_DSC(CHAR_INFO(curr_char_edge))->segment;
	    scr = sex_SegSegmentAtt_class_server_get(seg);
            if(sex_scr_font_len(scr)) {
              scr_font = sex_scr_font_get (scr, 0); 
              if(!strcmp(sex_scr_font_font_get(scr_font), "HAND")) {
                *is_script = 1;
                return 0;
              } 
            }
          }
        }
      }
    }
  }

  return 0;
}

/*++++
  Function:	aig_free
  Synopsis:	help function for exception handling
  Description:	reset the ai graph and calls ice_free for the given mark
  Input:	aigfree    - structure contains graph and ice mark
  Output:	
  Return:
++++*/ 

static void aig_free 
(
       aigFreeT    *aigfree
)
{
  memset(aigfree->cg, 0, sizeof(Graph));
  GRAPH_QUALIFIER(aigfree->cg) = CHAR_EDGE_LIST;
  GRAPH_STATUS(aigfree->cg)    = DIRTY_NON_TRIVIAL;
  ice_tfree(aigfree->mark);
  return;
}

/******************* I like the function headers very much!!! */

static char* PrintEdgeLength(char* buffer, Edge* edge) {
  if(EDGE_LENGTH(edge) > 0) {
    if(EDGE_LENGTH(edge) >= INFINITY) {
      sprintf(buffer + strlen(buffer), "l:INFINITY  \n");
    }
    else {
      sprintf(buffer + strlen(buffer), "l:%d  \n", (int) EDGE_LENGTH(edge));
    }
  }
  return buffer;
}

static void MarkCharEdges(char* pos, Edge* edge, va_list ap) {
  sex_scr *scr;
  const sex_scr_result    *result     = NULL;  /* B-nootbaar */
  const sex_scr_result_el *result_el  = NULL;
  unsigned                 result_len = 0;     /* E-nootbaar */
  char_info               *info;
  ObjDscT                 *obj_dsc;

    (void)ap;
    PrintEdgeLength(pos, edge);
    if((info=CHAR_INFO(edge))){
	if((obj_dsc=READ_OBJ_DSC(info))){
	  if(obj_dsc->segment){
	    scr = sex_SegSegmentAtt_class_server_get(obj_dsc->segment);
	    result = sex_scr_result_result(scr);
	    result_len = sex_scr_result_el_len (result); /* B-nootbaar */
	    if (result_len) {
	      result_el = sex_scr_result_el_get (result, 0);
	    }
	    sprintf(pos + strlen(pos), "\n\"%c\"   ",
		    result_len ?
		    sex_scr_result_el_code_class_get (result_el) :
		    '^');                                /* E-nootbaar */
	  }
	}
    }
}

static void mark_node(char *pos,Vertex* node,va_list ap) 
{
    (void)ap;
    sprintf(pos,"[%d]",(int)node->name);
}

ALIVE(ipif_obj,
      EXPORT_EXTERNAL_NAME(ipif, getSegmentationGraph);
      EXPORT_EXTERNAL_NAME(ipif, addClassifications);
      EXPORT_EXTERNAL_NAME(ipif, getClassification);
      EXPORT_EXTERNAL_NAME(ipif, getSegmentData);
      EXPORT_EXTERNAL_NAME(ipif, SegmentatorList2UINT32);
      EXPORT_EXTERNAL_NAME(ipif, getRegionText);
      EXPORT_EXTERNAL_NAME(ipif, getRegionFontStyles);
      EXPORT_EXTERNAL_NAME(ipif, getLineNumber);
      EXPORT_EXTERNAL_NAME(ipif, isScriptList);
      EXPORT_EXTERNAL_NAME(ipif, segmentsAreSameRegion);
)

