/*{{{  #includes*/
#ifdef CONFIG_H
#   include "config.h"
#endif

#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>

#include <local/bool.h>

#define ORIEDT_C
#define I_FOLDING_C
#define I_GETMSG_C
#define I_MAIN_C
#define I_MESSAGES_C
#define I_PROMPT_C
#define I_SIGNALS_C
#define I_STRING_C
#define I_VIRTUAL_C

#include "origami.h"
#include "macros.h"
/*}}}  */

/*{{{  size of element-blocks*/
#ifdef VIRTUAL
#  define NEW_ELEMENT_START (vir_nodes?NEW_ELEMENT_MAX:NEW_ELEMENT_LIMIT)
#else
#  define NEW_ELEMENT_START NEW_ELEMENT_LIMIT
#endif
/*}}}  */
/*{{{  variables*/
public bool fold_out=FALSE,fold_in=FALSE;
public element *dispose_head,*dispose_tail;
public int first_edit_pos,pre_edit_pos;
private element base_element[BASIC_ELEMENTS];
private element *el_ptr=base_element;
private int el_used=BASIC_ELEMENTS;
/*}}}  */

/*{{{  spaces                fill a string with spaces*/
public unsigned char *spaces(unsigned char *Result, int l)
{ if (l<0) return(Result);
  Result=Result+l;
  *(Result--)='\0';
  while (l-->0) *(Result--)=' ';
  return(Result+1);
}
/*}}}  */
/*{{{  trailing_spaces*/
public void trailing_spaces(unsigned char *s)
{
  unsigned char *x=s;
  unsigned char *y=s;

  while (*x) if (*x!=' ' && *x!='\t') y= ++x; else x++;
  *y='\0';
}
/*}}}  */
/*{{{  join_links*/
public void join_links(element *p,element *q)
{
  p->next = q;
  q->prec = p;
  if (filed_or_fold(p)) p->other_end->next = q;
}
/*}}}  */
/*{{{  move_on*/
public void move_on(element **p)
{
  if ((*p)->foldline == START_FOLD) *p = (*p)->fold; else *p = (*p)->next;
}
/*}}}  */
/*{{{  insert_indent_of*/
public int insert_indent_of(element *p)
{
  if (p->foldline == START_OPEN_FOLD)
    return (p->UU.U1.indent - p->UU.U1.fold_indent);
  else
    return (p->UU.U1.indent);
}
/*}}}  */
/*{{{  close_fold_at*/
public void close_fold_at(element *ptr)
{
  element *p;
  int i;

  p = ptr;
  /*{{{  start fold ?*/
  if (p->foldline == START_OPEN_FOLD) {
    p->foldline = START_FOLD;
    p->fold = p->next;
    p->next = p->other_end->next;
    p->next->prec = p;
  }
  /*}}}  */
  i = p->UU.U1.fold_indent;
  p->UU.U1.indent -= i;
  i += p->UU.U1.indent;
  p = p->fold;
  /*{{{  search matching end-fold*/
  while (p->foldline != END_FOLD) {
    if (p->foldline == START_OPEN_FOLD) close_fold_at(p);
    p->UU.U1.indent -= i;
    p = p->next;
  }
  /*}}}  */
  p->UU.U1.indent -= i;
}
/*}}}  */
/*{{{  proc_dispose*/
public void proc_dispose(element *p)
{
  join_links(dispose_tail, p);
  dispose_tail = p;
}
/*}}}  */
/*{{{  proc_new*/
public void proc_new(element **p)
{
  element *q;

  if (dispose_head != dispose_tail) {
    *p = dispose_head->next;
    /*{{{  maybe handle foldcontents*/
    if (filed_or_fold(*p)) {
      q = (*p)->other_end;
      (*p)->foldline = q->foldline = NOT_FOLD;
      if (dispose_tail == *p) dispose_tail = q;
      (*p)->next = (*p)->fold;
    }
    /*}}}  */
    /*{{{  join correct links*/
    if (dispose_tail == *p)
      dispose_tail = dispose_head;
    else
      join_links(dispose_head, (*p)->next);
    /*}}}  */
    set_data(*p,empty_text);
  } else {
    /*{{{  maybe get a new block of element-nodes*/
    if (!el_used) {
      /*{{{  malloc a new big element's-block*/
      el_used=NEW_ELEMENT_START;
      el_ptr=0;
      while (el_used && !(el_ptr=(element*)malloc(el_used*sizeof(element))))
        el_used=el_used>>1;
      if (!el_used) exit_origami(r_mem_full,M_NO_MEMORY);
      /*}}}  */
      /*{{{  maybe a warning not enough memory*/
      if (el_used<NEW_ELEMENT_LIMIT) {message(M_NO_MEMORY,TRUE);sleep(1);}
      /*}}}  */
    }
    /*}}}  */
    /*{{{  use element in allocated block*/
    *p=el_ptr++;
    el_used--;
    /*}}}  */
  }
  /*{{{  init data of new element*/
  **p = *null_item_ptr;
  /*}}}  */
}
/*}}}  */
/*{{{  proc_to_edit_pos*/
public void proc_to_edit_pos(void)
{
  pre_edit_pos = current->UU.U1.indent;
  first_edit_pos = pre_edit_pos + 1;
  if (filed_or_fold(current)) {
    pre_edit_pos = first_edit_pos + current->UU.U1.fold_indent;
    first_edit_pos = pre_edit_pos + (tag_length+1);
  }
  if (current->foldline == START_OPEN_FOLD || current->foldline == START_ENTER_FOLD) {
    pre_edit_pos = 0;
    first_edit_pos += (tag_length+1);
  }
  if (current->foldline == END_FOLD || current->foldline == START_ENTER_FILED) {
    pre_edit_pos = 0;
    first_edit_pos = LINELEN+1;
  }
}
/*}}}  */
/*{{{  proc_from_edit_pos*/
public void proc_from_edit_pos(void)
{
  if (filed_or_fold(current))
    current->UU.U1.fold_indent =
      strpos2(current_dsp_line,fold_line_str)-current->UU.U1.indent;
}
/*}}}  */
/*{{{  copyin*/
public void copyin(unsigned char *line,element *p,bool full)
{
  /*{{{  variables*/
  unsigned char fold_str[17];
  unsigned char l_buf[LINELEN+1];
  int  ind;
  /*}}}  */

  ind = p->UU.U1.indent;
  strcpy((char *)line,(char *)get_data(p));
  if (p->foldline == END_FOLD) {
    *line = '\0';
    if (fold_out) return;
  }
  if (full) trailing_spaces(line);
  *fold_str='\0';
  /*{{{  maybe prepare the foldstring*/
  if (p->foldline != NOT_FOLD) {
    /*{{{  handle fold-marks*/
    switch (p->foldline) {
      /*{{{  filed or fold*/
      case START_FOLD:
      case START_FILED:
        if (fold_out)
          spaces(fold_str,tag_length+1);
        else {
          if ( full )
            strcpy((char *)fold_str, (char *)fold_open_str);
          else
            strcpy((char *)fold_str, (char *)fold_line_str);
          strcat((char *)fold_str,(p->foldline==START_FILED?fold_f
                                                           :(char*)tspace+1));
        }
        ind += p->UU.U1.fold_indent;
        break;
      /*}}}  */
      /*{{{  begin fold*/
      case START_OPEN_FOLD:
      case START_ENTER_FOLD: {
        if (fold_out)
          spaces(fold_str,tag_length+1);
        else {
          strcpy((char *)fold_str,(char *)fold_open_str);
          strcat((char *)fold_str,(char*)tspace+1);
        }
        break;
      }
      /*}}}  */
      /*{{{  start enter filed*/
      case START_ENTER_FILED: {
        if (fold_out)
          spaces(fold_str,tag_length+1);
        else {
          ind=0;
          strcpy((char *)fold_str,(char *)fold_open_str);
          strcat((char *)fold_str,fold_f);
        }
        break;
      }
      /*}}}  */
      /*{{{  end fold*/
      case END_FOLD: {
        strcpy((char *)fold_str,(char *)fold_close_str);
        strcat((char*)fold_str,(char*)tspace+1);
        break;
      }
      /*}}}  */
      default: exit_origami(exit_failure,get_msg(M_INT_OCL));
    }
    /*}}}  */
    /*{{{  maybe add the commentstart to foldstring*/
    if (full) strinsert(dialect_start[dialect], fold_str);
    /*}}}  */
  }
  /*}}}  */
  /*{{{  build line from: indent,foldstring and text*/
  spaces(l_buf,ind);
  strcat((char *)l_buf,(char *)fold_str);
  strinsert(l_buf,line);
  /*}}}  */
  /*{{{  maybe add the comment-end*/
  if (p->foldline != NOT_FOLD && full)
    strcat((char *)line, (char *)dialect_end[dialect]);
  /*}}}  */
}
/*}}}  */
/*{{{  copyout*/
public void copyout(unsigned char *line,element *p)
{
  int i;

  if (p->foldline == NOT_FOLD)
    i = p->UU.U1.indent;
  else
    i = p->UU.U1.indent + (tag_length+1);
  if (filed_or_fold(p)) i += p->UU.U1.fold_indent;
  set_data(p,strsub(line,i+1));
}
/*}}}  */
