#include <execp.h>
#include <prefix.h>
#include <printapp.h>
#include <relation.h>
#include <tabutil.h>

// trasferimenti


class TField_text : public TObject
{
	int			_pos;
	int			_from;
	int			_to;
	
  struct TField_Flags
  {
    bool rightjust      : 1;
    byte trim           : 2;    // Trim the string 
    bool uppercase      : 1;
    bool zerofilled     : 1;
    
    char update(const char*);
    TField_Flags(const char* flags) {update(flags);}
    TField_Flags();
  } _flags;
protected:
	
public:
	TField_text(int pos, int from, int to, const char* flags);
	~TField_text();		
};

TField_text::TField_text(int pos, int from, int to, const char* flags)
{
	_pos = pos;
	_from = from;
	_to = to;
	_flags.update(flags);
};

TField_text::TField_Flags::TField_Flags()
{
  uppercase    = FALSE;
  rightjust    = FALSE;
  zerofilled 	 = FALSE;
  trim         = 3;
};

char TField_text::TField_Flags::update(const char* f)
{
  for (const char* s = f; *s; s++)
    switch(*s)
    {
    case '#':
      trim = 2; break;
    case '@':
      trim = 1; break;
    case ' ':  
    case '_':
      trim = 0; break;  
    case 'R': 
      rightjust = TRUE; break;
    case 'U': 
      uppercase = TRUE; break;
    case 'Z': 
      zerofilled = TRUE; break;
    default :  
      CHECKS(FALSE, "FLAG sconosciuto in ", f);
      break;
    }
  return *s;
}

class TRecord_text : TToken_string
{
	int _numrec;
public:
	const char* get_field(int pos, int from, int to);
	TRecord_text();
};

const char* TRecord_text::get_field(int pos, int from, int to)
{
	if (from == 0 && to == 0)
		return TToken_string::get(pos);
	else
	{
		TString record = TToken_string::get(0);
		return record.sub(from, to);
	}		
}

class TFiletext_len : public TObject
{
	char						_name[20];
	word						_len;
	TRecord_text*		_current;
	
public:
	TRecord_text& curr() {return *_current;}
};


class TTransfer : public TObject
{
	
	TCursor*		_cursor;
	TConfig*		_config;
	
	link_item* _pr_tree;
  int _cur_file;  
  
  link_item* _look_transf_node(link_item* head, int logicnum);
  void _reset_tree(link_item* head);
  
protected:	

	void create_cursor(TRelation* r, const char* filter, int nkey,
										 const TRectype *from, const TRectype* to);
	void create_config(const char* file);	
	virtual bool preprocess_record(int file, int counter) { return TRUE; }
	virtual bool preprocess_transf(int file, int counter) { return TRUE; }
	virtual bool postprocess_record(int file, int counter) { return TRUE; } 
	virtual bool postprocess_transf(int file, int counter) { return TRUE; } 
	
public:
  void reset_files();
  void add_file(int file, int from = 0);
  void add_file(const char* tab, int from = 0);
  
  bool add(TLocalisamfile* f, const char* relexprs, int key, int linkto,
  				 int alias, bool allow_lock);
  bool add(int logicnum, const char* relexprs, int key = 1, int linkto = 0,
  				 int alias = 0, bool allow_lock = FALSE);
  bool add(const char* tabname, const char* relexprs, int key = 1, int linkto = 0,
  				 int alias = 0, bool allow_lock = FALSE);
  
  bool do_load();
  bool do_dump();

  TTransfer();
  virtual ~TTransfer();

};

TTransfer::~TTransfer()
{
	if (_cursor != NULL)
		delete _cursor;
	if (_config != NULL)
		delete _config;
}

void TTransfer::create_cursor(TRelation* r, const char* filter, int nkey,
										 					const TRectype* from, const TRectype* to)
{
	CHECK(_cursor == NULL, "Il cursore esiste già");
	_cursor = new TCursor(r, filter, nkey, from, to);
}
										 					
void TTransfer::create_config(const char* file)
{
	CHECK(_config == NULL, "La configurazione esiste già");
	_config = new TConfig(file, "HEADER");
}

void TTransfer::_reset_tree(link_item* head)
{
  if (head)
  {
    if (head->_brother)
      _reset_tree(head->_brother);
    if (head->_son)
      _reset_tree(head->_son);
    delete head;
  }
}

link_item* TTransfer::_look_transf_node(link_item* head, int logicnum)
{
  link_item* s;
  while (head)
  {
    if (head->_logicnum == logicnum)
      return head;
    else if (head->_son) 
      if ((s = _look_transf_node(head->_son, logicnum)) != NULL)
        return s;
    head = head->_brother;
  }
  return NULL;
}

void TTransfer::add_file(const char* tab, int from)
{
  add_file(TTable::name2log(tab), from);
}

void TTransfer::add_file(int file, int from)
{  
  link_item *nw = new link_item(file);
  if (_pr_tree == NULL)
  {
    _pr_tree = nw;
    return;
  }
	  
  if (from == 0)
    from = _pr_tree->_logicnum;
	  
  link_item *fr = _look_transf_node(_pr_tree, from);
	  
  CHECKD(fr, "add_file: nonexistent node: logicnum = ", from);
	  
  if (fr->_son)
  {
    fr = fr->_son;
    while (fr->_brother)
      fr = fr->_brother;
    fr->_brother = nw;
  }
  else
    fr->_son = nw;
}

// aggiunge un file alla relazione del cursore (come add della TRelation)
bool TTransfer::add(TLocalisamfile* f, const char* relexprs, int key, int linkto,
  				 					int alias, bool allow_lock)
{
	return _cursor->relation()->add(f,	relexprs, key, linkto, alias, allow_lock);
}
  				 					
bool TTransfer::add(int logicnum, const char* relexprs, int key, int linkto,
  				 					int alias, bool allow_lock)
{
	return _cursor->relation()->add(logicnum,	relexprs, key, linkto, alias, allow_lock);
}  				 					
  				 					
bool TTransfer::add(const char* tabname, const char* relexprs, int key, int linkto,
  				 					int alias, bool allow_lock)
{
	return _cursor->relation()->add(tabname,	relexprs, key, linkto, alias, allow_lock);
}  				 					
  
bool TTransfer::do_load()
{
	CHECK((_config != NULL) && (_cursor != NULL), "Non esistono cursore o config");
	return TRUE;
}

bool TTransfer::do_dump()
{
	CHECK((_config != NULL) && (_cursor != NULL), "Non esistono cursore o config");
	
	return TRUE;
}
