#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <time.h>
#include "Logger.h"


const int  _num_of_log_header = 6;
const int  _debug_log_header_id = 5;

Logger::Logger( short mode ){ //{{{

   print_mode = mode;

   //Initialize log level
   debug_id = _debug_log_header_id;
   for( int i = 0;i < _num_of_log_header;i++){
      log_lv[i] = new LogLevel();
      log_lv[i]->set_header( (short)i );
   }

   function_name = "No Function";
} //}}}


//-- Public Function --//

int Logger::Log( std::string log , short log_level ){ //{{{

   short l = log_level;
   std::string buf_date = "";buf_date += GetDate();buf_date += " ";
   std::string buf_log = ""; buf_log += log;buf_log += " ";

   short mode = 0;
   if( print_mode > 0 ){
      if( (print_mode != 2) || ( l != 2 ) )mode = 1;
   }

   std::string buf_id = "";
   buf_id = "[";buf_id += Short2String( log_lv[0]->id );buf_id += "] ";
   log_lv[0]->set_header(l);
   log_lv[0]->set_log( buf_id , buf_date , buf_log , function_name , 0 );

   buf_id = "[";buf_id += Short2String( log_lv[l]->id );buf_id += "] ";
   log_lv[l]->set_log( buf_id , buf_date , buf_log , function_name , mode );


   return 1;
}

int Logger::Log( int log , short log_level ){
   Log( Int2String( log ) , log_level );
   return 1;
}
int Logger::Log( short log , short log_level ){
   Log( Short2String( log ) , log_level );
   return 1;
}
int Logger::Log( float log , short log_level ){
   Log( Float2String( log ) , log_level );
   return 1;
}
int Logger::Log( double log , short log_level ){
   Log( Double2String( log ) , log_level );
   return 1;
}
int Logger::Log( long log , short log_level ){
   Log( Long2String( log ) , log_level );
   return 1;
}//}}}

int Logger::Debug( std::string log ){ //{{{
   std::stringstream ss;
   ss << "Debug#(" << log_lv[debug_id]->id << "):" << log;

   std::string str;ss >> str;

   Log( str , debug_id );
   return 1;
}//}}}

int Logger::SetFunction( std::string function , int log_level , int print ){ //{{{
   function_name = function;

   if( print > 0 ){
      std::string str = "** Function <";str += function_name;str += "> **";
      Log( str , log_level );
   }

   return 1;
} //}}}

int Logger::Clear( void ){ //{{{
   for( int i = 0;i < _num_of_log_header;i++){
      log_lv[i]->txt = "";
      log_lv[i]->id = 0;
      log_lv[i]->log_txt = "";
      log_lv[i]->log_id = "";
      log_lv[i]->log_date = "";
   }

   function_name = "No Function";
   return 1;
} //}}}

int Logger::Read( std::string input_name ){ //{{{
   std::ifstream ifs( input_name.c_str() );

   std::string buf_line;
   short last_level = 0;
   while( ifs && getline( ifs , buf_line ) ){
      std::vector<std::string> sp = split( buf_line , " " );
      short log_level = -1;
      for( short l = 0;l < _num_of_log_header;l++){
         std::string header = log_lv[0]->set_header(l);
         std::string::size_type index = buf_line.find( header );
         if( index != std::string::npos ) log_level = l; //Check Log level
      }
      log_lv[0]->set_header(0);

      log_lv[0]->txt += buf_line;
      log_lv[0]->txt += "\n";
      if( log_level > 0 ){
         log_lv[log_level]->txt += buf_line;
         log_lv[log_level]->txt += "\n";

         for( int i = 0;i < sp.size();i++){

            //id
            if( i == 0){ //id
               log_lv[0]->log_id += sp[0];
               log_lv[0]->log_id += " ";
               log_lv[log_level]->log_id += sp[0];
               log_lv[log_level]->log_id += " ";
            }else if( i == 1 ){ //date 
               log_lv[0]->log_date += sp[1];
               log_lv[0]->log_date += " ";
               log_lv[log_level]->log_date += sp[1];
               log_lv[log_level]->log_date += " ";
            }else if( i > 2 ){ //data
               log_lv[0]->log_txt += sp[i];
               log_lv[0]->log_txt += " ";
               log_lv[log_level]->log_txt += sp[i];
               log_lv[log_level]->log_txt += " ";
            }
         }
      }else{
         //Data search
         log_lv[0]->log_txt += buf_line;
         if( last_level > 0){
            log_lv[last_level]->txt += buf_line;
            log_lv[last_level]->log_txt += buf_line;
         }
      }

      last_level = ( log_level > 0 ) ? log_level : last_level;
   }

   return 1;
} //}}}

int Logger::GetSize( short log_level ){ //{{{
   return log_lv[log_level]->id;
} //}}}

int Logger::Print( short log_level ){ //{{{ 0:All,1:Info,2:Data,3:Warning,4:Error
   std::cout << log_lv[ log_level ]->txt;
   return 1;
} //}}}

int Logger::Write( std::string output_file , short log_level , short write_mode , short log_num ){ //{{{Output file
   std::ofstream ofs;
   if( write_mode ){
      ofs.open( output_file.c_str() , std::ios::out | std::ios::app );
   }else{
      ofs.open( output_file.c_str() , std::ios::out | std::ios::trunc );
   }

   std::string str;
   switch( log_num ){
      case 0:
         str = log_lv[log_level]->txt;
         break;
      case 1:
         str = log_lv[log_level]->log_id;
         break;
      case 2:
         str = log_lv[log_level]->log_date;
         break;
      case 3:
         str = log_lv[log_level]->log_txt;
         break;
   }
   ofs << str;
   ofs.close();

   std::cout << "[Logger_Message]Output Log file to \" " << output_file << " \" " << std::endl;

   return 1;
} //}}}

std::string Logger::GetLogString( short log_level , short log_num ){//{{{ log_num 0: all , 1:id , 2: date , 3: text
   std::string str;
   short l = log_level;
   switch( log_num ){
      case 0:
         str = log_lv[l]->txt;
         break;
      case 1:
         str = log_lv[l]->log_id;
         break;
      case 2:
         str = log_lv[l]->log_date;
         break;
      case 3:
         str = log_lv[l]->log_txt;
         break;
   }
   return str;
} //}}}


//-- Private Function --//

std::string Logger::GetDate( void ){ //{{{

   struct tm *date;
   time_t now;
   int year, month, day;
   int hour, minute, second;

   time(&now);
   date = localtime(&now);

   year = date->tm_year + 1900;
   month = date->tm_mon + 1;
   day = date->tm_mday;
   hour = date->tm_hour;
   minute = date->tm_min;
   second = date->tm_sec;

   std::stringstream ss;
   ss <<  year << "/" << month << "/" << day << "_" << hour << ":" << minute << ":" << second ;
   std::string str;ss >> str ;

   return str;
} //}}}

std::string Logger::Int2String( int i ){ //{{{
   std::stringstream ss;ss << i ;
   std::string str;ss >> str ;
   return str;
}
std::string Logger::Short2String( short i ){ 
   std::stringstream ss;ss << i ;
   std::string str;ss >> str ;
   return str;
}
std::string Logger::Float2String( float i ){ 
   std::stringstream ss;ss << i ;
   std::string str;ss >> str ;
   return str;
}
std::string Logger::Double2String( double i ){ 
   std::stringstream ss;ss << i ;
   std::string str;ss >> str ;
   return str;
}
std::string Logger::Long2String( long i ){ 
   std::stringstream ss;ss << i ;
   std::string str;ss >> str ;
   return str;
}//}}}

std::vector<std::string> Logger::split(std::string str, std::string delim) { //{{{
   std::vector<std::string> items;
   std::size_t dlm_idx;
   if(str.npos == (dlm_idx = str.find_first_of(delim))) {
      items.push_back(str.substr(0, dlm_idx));
   }
   while(str.npos != (dlm_idx = str.find_first_of(delim))) {
      if(str.npos == str.find_first_not_of(delim)) {
         break;
      }
      items.push_back(str.substr(0, dlm_idx));
      dlm_idx++;
      str = str.erase(0, dlm_idx);
      if(str.npos == str.find_first_of(delim) && "" != str) {
         items.push_back(str);
         break;
      }
   }
   return items;
} //}}}

