/****************************************************************************************/
/*  INPUT.C                                                                             */
/*                                                                                      */
/*  Author: Timothy Roff	                                                            */
/*  Description:  Shader implementation                                                 */
/*                                                                                      */
/*  The contents of this file are subject to the Jet3D Public License                   */
/*  Version 1.02 (the "License"); you may not use this file except in                   */
/*  compliance with the License. You may obtain a copy of the License at                */
/*  http://www.jet3d.com                                                                */
/*                                                                                      */
/*  Software distributed under the License is distributed on an "AS IS"                 */
/*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
/*  the License for the specific language governing rights and limitations              */
/*  under the License.                                                                  */
/*                                                                                      */
/*  This file was not part of the original Jet3D, released December 12, 1999.           */
/*                                                                                      */
/****************************************************************************************/

#include "jeShaderDefs.h"
#include "jeShader_h.h"


//=====================================================================================
//	jeShader_Input
//=====================================================================================
int jeShader_Input(shader_info_t *info)
{
   int cin;
   	assert(info != NULL);

   if (info->uninputted) {
      cin = info->uninput_cin;
      info->uninputted = JE_FALSE;
   }
   else {
      cin = jeShader_GetInput(info);
   }

   if (cin == '\n') {
      info->next_line_count++;
   }

   return cin;
}

//=====================================================================================
//	jeShader_InputUnget
//=====================================================================================
void jeShader_InputUnget(int cin, shader_info_t *info)
{
	assert(info != NULL);

   info->uninput_cin = cin;
   info->uninputted  = JE_TRUE;
}


//=====================================================================================
//	jeShader_GetInput
//=====================================================================================
int jeShader_GetInput(shader_info_t *info)
{
	assert(info != NULL);

	return getc(info->shader_file);
}

//=====================================================================================
//	jeShader_SetInput
//=====================================================================================
jeBoolean jeShader_SetInput(FILE* f, shader_info_t *info)
{
	assert(info != NULL);
	info->shader_file = f;

	return JE_TRUE;

}



//=====================================================================================
//	jeShader_BeginScan
//=====================================================================================
void jeShader_BeginScan(shader_info_t *info)
{
	assert(info != NULL);

   info->brace_count     = 0;
   info->jet_shader_line_count  = 1;
   info->next_line_count = 1;
}


//=====================================================================================
//	jeShader_EndScan
//=====================================================================================
void jeShader_EndScan(shader_info_t *info)
{
	assert(info != NULL);

   info->brace_count      = 0;
   info->jet_shader_line_count   = 0;
   info->next_line_count  = 0;
}


void end_of_input(shader_info_t *info)
{
	assert(info != NULL);

   strncpy(info->token.string, "<EOF>", JE_SHADER_TOKEN_LEN);

   if (info->brace_count > 0) {
	   jeShader_Error("%d extra opening brace%s detected in file", (info->brace_count > 1)?("s "):(" "), info->brace_count);

   }
   else if (info->brace_count < 0) {
      jeShader_Error("%d extra closing brace%s detected in file", (info->brace_count < -1)?("s "):(" "), -info->brace_count);
   }
}


//=====================================================================================
//	jeShader_Scan
//=====================================================================================
JE_SHADER_TOKEN jeShader_Scan(shader_info_t *info)
{
	int cin;

   	assert(info != NULL);

   info->token.string[0]  = '\0';
   info->token.is_newline = JE_FALSE;

   info->jet_shader_line_count = info->next_line_count;

   for (;;) {
      do {
         cin = jeShader_Input(info);

         if (cin == '\n') info->token.is_newline = JE_TRUE;

      } while (isspace(cin));

      if (cin == '/') {
         cin = jeShader_Input(info);

         if (cin == '/') {
            do {
               cin = jeShader_Input();
            } while ((cin != '\n') && (cin != EOF));

            if (cin == '\n') info->token.is_newline = JE_TRUE;

            if (cin == EOF) {
               end_of_input(info);
               return JE_SHADER_TOKEN_EOF;
            }
         }
         else {
            jeShader_InputUnget(cin, info);
            break;
         }
      }
      else {
         break;
      }
   }

   if (cin != EOF) {
      int pos = 0;

      do {
         info->token.string[pos] = (char)cin;
         cin = jeShader_Input(info);

         // If the token is too big then it will be truncated to a size
         // one larger than is allowable.  The overflow can then be
         // detected and reported by the consumer of the token.
         if (pos < JE_SHADER_TOKEN_LEN) pos++;
      } while (!isspace(cin) && (cin != EOF));

      jeShader_InputUnget(cin, info);

      info->token.string[pos] = '\0';

      if (strcmp("{", info->token.string) == 0) {
         info->brace_count++;

         if (info->brace_count > 2) jeShader_Error("'{' (opening braces) should never be nested more than 2 deep");

         return '{';
      }
      else if (strcmp("}", info->token.string) == 0) {
         info->brace_count--;

         if (info->brace_count < 0) jeShader_Error("extra '}' (closing brace) detected");

         return '}';
      }
	  else {
         return JE_SHADER_TOKEN_STRING;
      }
   }
   else {
      end_of_input(info);
      return JE_SHADER_TOKEN_EOF;
   }
}

//=====================================================================================
//	jeShader_Skip
//=====================================================================================
jeBoolean jeShader_Skip(shader_info_t *info)
{
	assert(info != NULL);

   while (info->brace_count == 0) {
      if (jeShader_Scan(info) == JE_SHADER_TOKEN_EOF) return JE_TRUE;
   }

   while (info->brace_count != 0) {
      if (jeShader_Scan(info) == JE_SHADER_TOKEN_EOF) return JE_TRUE;
   }

   return JE_TRUE;
}


//EOF