/*
 * @author fenrir (http://fenrir.naruoka.org/)
 * 
 * reg_core.c
 * スキャンやマッチなどのコンパイル後の動作
 */

#include "reg_core.h"
#include "reg_util.h"
#include "reg_char.h"
#include <string.h>

#ifdef __cplusplus
extern "C"{
#endif

#define DEBUG 0

/**
 * コンパイル済み正規表現で文字列をスキャンします。
 * 
 * @param regexp コンパイル済み正規表現
 * @param target ターゲット文字列
 * @param stack スタック
 * @return 結果、スキャンに成功しなかった場合はNULL
 */
static reg_match_t *scan(regexp_t *regexp, char *target, reg_stack_t *stack){
 
  regexp->status = 0;
  stack->top = stack->bottom;
  stack->top->node = regexp->list.top;
  stack->top->input_index = target;
  
  reg_state_t *current;
  while((current = (stack->top)--) >= stack->bottom){

#if DEBUG
    printf("NODE_ID:\t%d\n", current->node);
    printf("SIZE:\t%d\n", current - stack->bottom + 1);
    printf("INFO:\t%d\n", current->node->info);
    printf("INPUT_INDEX:\t%s\n", current->input_index);
#endif

    if(current->node == regexp->list.end){
      reg_match_t *match_object = &(regexp->match_object);
      reg_submatch_t *submatch;
      for(submatch = match_object->submatch_top; submatch < match_object->submatch_end; submatch++){
        find_submatch(submatch, stack);
      }
      return match_object;
    }

    if(!(current->node->transit(current, stack))){break;}
  }
  
  return NULL;
}

/**
 * コンパイル済み正規表現で文字列をスキャンします。
 * 
 * @param regexp コンパイル済み正規表現
 * @param target ターゲット文字列
 * @param buffer_size 内部スタックのサイズ
 * @return 結果、スキャンに成功しなかった場合はNULL
 */
reg_match_t *reg_scan(regexp_t *regexp, char *target, int buffer_size){

  reg_stack_t stack;
  reg_state_t states[buffer_size];
  stack.bottom = states;
  stack.size = buffer_size;
  
  return scan(regexp, target, &stack);
}

/**
 * コンパイル済み正規表現と文字列とのマッチを行います。
 * 
 * @param regexp コンパイル済み正規表現
 * @param target ターゲット文字列
 * @param buffer_size 内部スタックのサイズ
 * @return 結果、マッチしなかった場合はNULL
 */
reg_match_t *reg_match(regexp_t *regexp, char *target, int buffer_size){

  reg_stack_t stack;
  reg_state_t states[buffer_size];
  stack.bottom = states;
  stack.size = buffer_size;
  
  reg_match_t *match_object;
  while(*target){
    if(match_object = scan(regexp, target, &stack)){return match_object;}
    target = reg_char_shift(target, 1);
  }
  
  return NULL;
}

/**
 * 部分マッチの結果を返します。
 * 
 * @param match_object マッチ結果
 * @param index 部分マッチのインデックス
 * @param dist 結果のコピー先
 * @param buffer_size コピー先の大きさ
 * @return 部分マッチの結果があって、かつ結果が正しくコピーされた場合dist、それ以外NULL
 */
char *reg_submatch(reg_match_t *match_object, int index, char *dist, int buffer_size){
  
  reg_submatch_t *target = match_object->submatch_top + index;
  if(target >= match_object->submatch_end){return NULL;}
  
  int len = target->range.end - target->range.start;
  if(len < 0){len = 0;}
  if(len >= buffer_size){return NULL;}
  
  memcpy(dist, target->range.start, len);
  *(dist + len) = '\0';
  return dist;
}

#ifdef __cplusplus
};
#endif
