/***************************************************************
 * Name:      codestatexec.cpp
 * Purpose:   Code::Blocks Profiler plugin: main window
 * Author:    Zlika
 * Created:   11/09/2005
 * Copyright: (c) Zlika
 * License:   GPL
 **************************************************************/

#include "codestatexec.h"

int CodeStatExecDlg::Execute(LanguageDef languages[NB_FILETYPES])
{
	int i, j, l, num_language;
   long int total_lines = 0;
   long int code_lines = 0;
   long int empty_lines = 0;
   long int comment_lines = 0;
   long int codecomments_lines = 0;
   long int nb_files = 0;
   long int nb_skipped_files = 0;
   long int nb_files_not_found = 0;

   cbProject* project = Manager::Get()->GetProjectManager()->GetActiveProject();
   nb_files = project->GetFilesCount();
   //wxMessageBox(wxString::Format(_T("Nb files: %ld"), nb_files), _("Error"), wxOK);
   wxProgressDialog progress(_("Code Statistics plugin"),_("Parsing project files. Please wait..."));
   for (i=0; i<nb_files; i++)
   {
   	ProjectFile* pf = project->GetFile(i);
      wxFileName filename;
      filename = pf->file;
   	if (!filename.FileExists())
   	{
   		nb_files_not_found++;
   		//Manager::Get()->GetMessageManager()->DebugLog(_("Code Statistics: Ignoring file '%s' (file not found)"), filename.GetName());
   	}
   	else
   	{
   		// Find the language associated to the file extension
   		num_language = -1;
   		for (l=0; l<NB_FILETYPES; l++)
   		{
   			for (j=0; j<languages[l].ext.Count(); j++)
   			{
   		      if (filename.GetExt() == languages[l].ext[j])
   		         num_language = l;
   			}
   		}

   		// If the language is found, analyse the source file
   		if (num_language > -1)
   	      CountLines(filename, languages[num_language], code_lines, codecomments_lines, comment_lines, empty_lines, total_lines);
         else nb_skipped_files++;
   	}

      if (nb_files > 1)
         progress.Update((100*i)/(nb_files-1));
   }
   progress.Update(100);

   // Setting-up the statistics dialog box
   wxXmlResource::Get()->LoadDialog(this, parent, _T("dlgCodeStatExec"));

   wxStaticText* txt_num_files = XRCCTRL(*this, "txt_num_files", wxStaticText);
   txt_num_files->SetLabel(wxString::Format(_("%ld"), nb_files));
   wxStaticText* txt_skipped_files = XRCCTRL(*this, "txt_skipped_files", wxStaticText);
   txt_skipped_files->SetLabel(wxString::Format(_("%ld"), nb_skipped_files));
   wxStaticText* txt_files_not_found = XRCCTRL(*this, "txt_files_not_found", wxStaticText);
   txt_files_not_found->SetLabel(wxString::Format(_("%ld"), nb_files_not_found));

   wxStaticText* txt_Code = XRCCTRL(*this, "txt_Code", wxStaticText);
   txt_Code->SetLabel(wxString::Format(_("%ld"), code_lines));
   wxStaticText* txt_Empty = XRCCTRL(*this, "txt_Empty", wxStaticText);
   txt_Empty->SetLabel(wxString::Format(_("%ld"), empty_lines));
   wxStaticText* txt_Comments = XRCCTRL(*this, "txt_Comments", wxStaticText);
   txt_Comments->SetLabel(wxString::Format(_("%ld"), comment_lines));
   wxStaticText* txt_Code_Comments = XRCCTRL(*this, "txt_Code_Comments", wxStaticText);
   txt_Code_Comments->SetLabel(wxString::Format(_("%ld"), codecomments_lines));
   wxStaticText* txt_Total = XRCCTRL(*this, "txt_Total", wxStaticText);
   txt_Total->SetLabel(wxString::Format(_("%ld"), total_lines));

   wxGauge* Gauge_Code = XRCCTRL(*this, "Gauge_Code", wxGauge);
   Gauge_Code->SetValue((100*code_lines)/total_lines);
   wxStaticText* txt_Gauge_Code = XRCCTRL(*this, "txt_Gauge_Code", wxStaticText);
   txt_Gauge_Code->SetLabel(wxString::Format(_("%3d%% Code only"), (100*code_lines)/total_lines));
   wxGauge* Gauge_Code_Comments = XRCCTRL(*this, "Gauge_Code_Comments", wxGauge);
   Gauge_Code_Comments->SetValue((100*codecomments_lines)/total_lines);
   wxStaticText* txt_Gauge_Code_Comments = XRCCTRL(*this, "txt_Gauge_Code_Comments", wxStaticText);
   txt_Gauge_Code_Comments->SetLabel(wxString::Format(_("%3d%% Code + Comment"), (100*codecomments_lines)/total_lines));
   wxGauge* Gauge_Comments = XRCCTRL(*this, "Gauge_Comments", wxGauge);
   Gauge_Comments->SetValue((100*comment_lines)/total_lines);
   wxStaticText* txt_Gauge_Comments = XRCCTRL(*this, "txt_Gauge_Comments", wxStaticText);
   txt_Gauge_Comments->SetLabel(wxString::Format(_("%3d%% Comments"), (100*comment_lines)/total_lines));
   wxGauge* Gauge_Empty = XRCCTRL(*this, "Gauge_Empty", wxGauge);
   Gauge_Empty->SetValue((100*empty_lines)/total_lines);
   wxStaticText* txt_Gauge_Empty = XRCCTRL(*this, "txt_Gauge_Empty", wxStaticText);
   txt_Gauge_Empty->SetLabel(wxString::Format(_("%3d%% Empty"), (100*empty_lines)/total_lines));

   ShowModal();

   return 0;
}

void CodeStatExecDlg::EndModal(int retCode)
{
    wxDialog::EndModal(retCode);
}

void CodeStatExecDlg::CountLines(wxFileName filename, LanguageDef &language,
                                 long int &code_lines, long int &codecomments_lines,
                                 long int &comment_lines, long int &empty_lines, long int &total_lines)
{
	wxString line;
	wxTextFile file;
	bool comment, code, multi_line_comment;

	if (file.Open(filename.GetFullPath()))
	{
		multi_line_comment = false;
		total_lines += file.GetLineCount();
		for (unsigned int i=0; i<file.GetLineCount(); i++)
		{
		   line = file[i];
		   line = line.Trim(true);
         line = line.Trim(false);
		   comment = false;
		   code = false;
		   if (line.IsEmpty())
	         empty_lines++;
		   else
		   {
		   	AnalyseLine(language, line, comment, code, multi_line_comment);
		      if (comment&&code) codecomments_lines++;
		      else if (comment) comment_lines++;
		      else if (code) code_lines++;
		   }
		}
	}
}

void CodeStatExecDlg::AnalyseLine(LanguageDef &language, wxString line, bool &comment, bool &code, bool &multi_line_comment)
{
   int first_single_line_comment, first_multi_line_comment_begin, first_multi_line_comment_end;

   // Delete first and trailing spaces
   line = line.Trim(true);
   line = line.Trim(false);

	if (line.IsEmpty())
	   return;

	// Searching for single and multi-lines comment signs
	if (language.single_line_comment.Length() > 0)
      first_single_line_comment = line.Find(language.single_line_comment);
   else first_single_line_comment = -1;
   if (language.multiple_line_comment[0].Length() > 0)
      first_multi_line_comment_begin = line.Find(language.multiple_line_comment[0]);
   else first_multi_line_comment_begin = -1;
   if (language.multiple_line_comment[1].Length() > 0)
      first_multi_line_comment_end = line.Find(language.multiple_line_comment[1]);
   else first_multi_line_comment_end = -1;

   // We are in a multiple line comment => finding the "end of multiple line comment" sign
   if (multi_line_comment)
   {
      comment = true;
   	if (first_multi_line_comment_end > -1)
   	{
   		multi_line_comment = false;
   		if (first_multi_line_comment_end+language.multiple_line_comment[1].Length() < line.Length())
   		   AnalyseLine(language, line.Mid(first_multi_line_comment_end+language.multiple_line_comment[1].Length()), comment, code, multi_line_comment);
   	}
   }
   // We are not in a multiple line comment
   else if (!multi_line_comment)
   {
   	// First comment sign found is a single line comment sign
      if ( (first_single_line_comment>-1)
         &&((first_multi_line_comment_begin==-1)||((first_multi_line_comment_begin>-1)&&(first_single_line_comment<first_multi_line_comment_begin))) )
      {
      	comment = true;
         if (first_single_line_comment > 0)
            code = true;
      }
      // First comment sign found is a multi-line comment begin sign
      else if (first_multi_line_comment_begin>-1)
      {
         multi_line_comment = true;
         comment = true;
         if (first_multi_line_comment_begin > 0)
            code = true;
         if (first_multi_line_comment_begin+language.multiple_line_comment[0].Length() < line.Length())
   		   AnalyseLine(language, line.Mid(first_multi_line_comment_begin+language.multiple_line_comment[0].Length()), comment, code, multi_line_comment);
      }
      else
      {
      	code = true;
      }
   }
}

CodeStatExecDlg::~CodeStatExecDlg()
{
}


syntax highlighted by Code2HTML, v. 0.9.1