/***************************************************************
 * Name:      cbprofilerexec.cpp
 * Purpose:   Code::Blocks Profiler plugin: main window
 * Author:    Dark Lord & Zlika
 * Created:   07/20/05 21:54:15
 * Copyright: (c) Dark Lord & Zlika
 * Thanks:    Yiannis Mandravellos and his Source code formatter (AStyle) sources
 * License:   GPL
 **************************************************************/

#include "cbprofilerexec.h"

BEGIN_EVENT_TABLE(CBProfilerExecDlg, wxDialog)
EVT_LIST_ITEM_ACTIVATED(XRCID("lstFlatProfile"), CBProfilerExecDlg::FindInCallGraph)
EVT_BUTTON(XRCID("btnExport"), CBProfilerExecDlg::WriteToFile)
END_EVENT_TABLE()

// This function retrieve the selected function in the call graph tab
void CBProfilerExecDlg::FindInCallGraph(wxListEvent& event)
{
	 // We retrieve the name of the function on the line selected
	 wxListItem item;
	 item.m_itemId = event.GetIndex();
	 item.m_col = 6;
	 item.m_mask = wxLIST_MASK_TEXT;
	 outputFlatProfileArea->GetItem(item);
	 wxString function_name = item.m_text;

	 // Then search this name in the call graph
	 wxString indexColumn, functionColumn;
	 size_t n;
	 for (n=0; n<(size_t)outputCallGraphArea->GetItemCount(); n++)
	 {
	 	 item.Clear();
	 	 item.m_itemId = n;
	 	 item.m_col = 0;
	 	 item.m_mask = wxLIST_MASK_TEXT;
	 	 outputCallGraphArea->GetItem(item);
	 	 indexColumn = item.m_text;
       if ((indexColumn.Mid(0,1)).CompareTo(_T("[")) == 0)
       {
          item.Clear();
	 	    item.m_itemId = n;
	 	    item.m_col = 5;
	 	    item.m_mask = wxLIST_MASK_TEXT;
	 	    outputCallGraphArea->GetItem(item);
	 	    functionColumn = item.m_text;
	 	    if (functionColumn.Find(function_name) != -1)
	 	       break;
       }
	 }

	 // Scrolling to the desired line in the "Call Graph" tab
	 if (n < (size_t)outputCallGraphArea->GetItemCount())
	 {
       outputCallGraphArea->EnsureVisible(n);
       XRCCTRL(*this, "tabs", wxNotebook)->SetSelection(1);
	 }
}

int CBProfilerExecDlg::Execute(wxString exename, wxString dataname, struct_config config)
{
    //this->parent = parent;

    // gprof optional parameters
    wxString param = config.txtExtra;
    if (config.chkAnnSource) param << _T(" -A") << config.txtAnnSource;
    if (config.chkMinCount) param << _T(" -m ") << config.spnMinCount;
    if (config.chkBrief) param << _T(" -b");
    if (config.chkFileInfo) param << _T(" -i");
    if (config.chkNoStatic) param << _T(" -a");
    if (config.chkSum) param << _T(" -s");

    wxString cmd;
    cmd << _T("gprof ") << param << _T(" \"") << exename << _T("\" \"") << dataname << _T("\"");

    wxProgressDialog progress(_("C::B Profiler plugin"),_("Launching gprof. Please wait..."));
    int pid = wxExecute(cmd, gprof_output, gprof_errors);
    progress.Update(100);

    if (pid == -1)
    {
        wxString msg = _("Unable to execute Gprof\nBe sure it is in the OS global path\nC::B Profiler could not complete the operation");
        wxMessageBox(msg, _("Error"), wxICON_ERROR | wxOK);
        Manager::Get()->GetMessageManager()->DebugLog(msg);

        return -1;
    }
    else
    {
        wxXmlResource::Get()->LoadDialog(this, parent, _T("dlgCBProfilerExec"));
        wxFont font(10, wxMODERN, wxNORMAL, wxNORMAL);
        outputFlatProfileArea=XRCCTRL(*this, "lstFlatProfile", wxListCtrl);
        outputHelpFlatProfileArea=XRCCTRL(*this, "txtHelpFlatProfile", wxTextCtrl);
        outputHelpFlatProfileArea->SetFont(font);
        outputCallGraphArea=XRCCTRL(*this, "lstCallGraph", wxListCtrl);
        outputHelpCallGraphArea=XRCCTRL(*this, "txtHelpCallGraph", wxTextCtrl);
        outputHelpCallGraphArea->SetFont(font);
        outputMiscArea=XRCCTRL(*this, "txtMisc", wxTextCtrl);
        outputMiscArea->SetFont(font);

        if(!gprof_output.IsEmpty())
            ShowOutput(gprof_output, false);
        else
            ShowOutput(gprof_errors, true);
    }

    return 0;
}

void CBProfilerExecDlg::ShowOutput(wxArrayString msg, bool error)
{
    size_t   n;
    wxString output;
    size_t   count = msg.GetCount();
    if ( !count )
        return;

   if (!error)
   {
      wxProgressDialog progress(_("C::B Profiler plugin"),_("Parsing profile information. Please wait..."));
      // Parsing Flat Profile
      n = 0;
      if (msg[n].Find(_T("Flat profile")) != -1)
         n = ParseFlatProfile(msg, n);
      progress.Update(50);

      // Parsing Call Graph
      if (msg[n].Find(_T("Call graph")) != -1)
         n = ParseCallGraph(msg, ++n);
      progress.Update(90);

      // The rest of the lines, if any, is printed in the Misc tab
      for ( ; n < count; n++ )
      {
         output << msg[n] << _T("\n");
      }
      outputMiscArea->SetValue(output);
      progress.Update(100);
   }
    else
    {
    	  for ( n = 0; n < count; n++ )
        {
            output << msg[n] << _T("\n");
        }
        outputMiscArea->SetValue(output);
        wxColour color(255,0,0);
        outputMiscArea->SetForegroundColour(color);
    }
    ShowModal();
}

CBProfilerExecDlg::~CBProfilerExecDlg()
{
}

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

size_t CBProfilerExecDlg::ParseCallGraph(wxArrayString msg, size_t begin)
{
	size_t   n;
	size_t next = 0;
	char first_char;
	wxString output_help;

	// Setting colums names
	outputCallGraphArea->InsertColumn(0, _T("index"));
	outputCallGraphArea->InsertColumn(1, _T("% time"));
	outputCallGraphArea->InsertColumn(2, _T("self"));
	outputCallGraphArea->InsertColumn(3, _T("children"));
	outputCallGraphArea->InsertColumn(4, _T("called"));
	outputCallGraphArea->InsertColumn(5, _T("name"));

	// Jump header lines
	while ((begin < msg.GetCount())&&(msg[begin].Find(_T("index % time")) == -1))
	   begin++;
   begin++;

   // Parsing Call Graph
   for (n = begin ; n < msg.GetCount(); n++ )
   {
      if ((msg[n].IsEmpty())||(msg[n].Find(0x0C) != -1))
    	   break;
      outputCallGraphArea->InsertItem(next,_T(""));
      first_char = msg[n].GetChar(0);
      if (first_char == '-')
         continue;
      outputCallGraphArea->SetItem(next, 0, ((msg[n].Mid(0,6)).Trim(true)).Trim(false));
      outputCallGraphArea->SetItem(next, 1, ((msg[n].Mid(6,6)).Trim(true)).Trim(false));
      outputCallGraphArea->SetItem(next, 2, ((msg[n].Mid(12,8)).Trim(true)).Trim(false));
      outputCallGraphArea->SetItem(next, 3, ((msg[n].Mid(20,8)).Trim(true)).Trim(false));
      outputCallGraphArea->SetItem(next, 4, ((msg[n].Mid(28,17)).Trim(true)).Trim(false));
      outputCallGraphArea->SetItem(next, 5, msg[n].Mid(45));
      next++;
   }

   // Resize columns
   outputCallGraphArea->SetColumnWidth(0, wxLIST_AUTOSIZE_USEHEADER );
   outputCallGraphArea->SetColumnWidth(1, wxLIST_AUTOSIZE_USEHEADER );
   outputCallGraphArea->SetColumnWidth(2, wxLIST_AUTOSIZE_USEHEADER );
   outputCallGraphArea->SetColumnWidth(3, wxLIST_AUTOSIZE_USEHEADER );
   outputCallGraphArea->SetColumnWidth(4, wxLIST_AUTOSIZE_USEHEADER );
   outputCallGraphArea->SetColumnWidth(5, wxLIST_AUTOSIZE);

   // Printing Call Graph Help
   for ( ; n < msg.GetCount(); n++ )
   {
      if (msg[n].Find(0x0C) != -1)
         break;
      output_help << msg[n] << _T("\n");
   }
   outputHelpCallGraphArea->SetValue(output_help);

   return ++n;
}

size_t CBProfilerExecDlg::ParseFlatProfile(wxArrayString msg, size_t begin)
{
	size_t   n;
	size_t next = 0;
	wxString output_help;

	// Setting colums names
	outputFlatProfileArea->InsertColumn(0, _T("% time"));
	outputFlatProfileArea->InsertColumn(1, _T("cum. sec."));
	outputFlatProfileArea->InsertColumn(2, _T("self sec."));
	outputFlatProfileArea->InsertColumn(3, _T("calls"));
	outputFlatProfileArea->InsertColumn(4, _T("self s/call"));
	outputFlatProfileArea->InsertColumn(5, _T("total s/call"));
	outputFlatProfileArea->InsertColumn(6, _T("name"));

	// Jump header lines
	while ((begin < msg.GetCount())&&(msg[begin].Find(_T("Ts/call")) == -1))
	   begin++;
   begin++;

   // Parsing Call Graph
   for (n = begin ; n < msg.GetCount(); n++ )
   {
      if ((msg[n].IsEmpty())||(msg[n].Find(0x0C) != -1))
    	   break;
      outputFlatProfileArea->InsertItem(next,_T(""));
      outputFlatProfileArea->SetItem(next, 0, ((msg[n].Mid(0,6)).Trim(true)).Trim(false));
      outputFlatProfileArea->SetItem(next, 1, ((msg[n].Mid(6,10)).Trim(true)).Trim(false));
      outputFlatProfileArea->SetItem(next, 2, ((msg[n].Mid(16,9)).Trim(true)).Trim(false));
      outputFlatProfileArea->SetItem(next, 3, ((msg[n].Mid(25,9)).Trim(true)).Trim(false));
      outputFlatProfileArea->SetItem(next, 4, ((msg[n].Mid(34,9)).Trim(true)).Trim(false));
      outputFlatProfileArea->SetItem(next, 5, ((msg[n].Mid(43,9)).Trim(true)).Trim(false));
      outputFlatProfileArea->SetItem(next, 6, ((msg[n].Mid(52)).Trim(true)).Trim(false));
      next++;
   }

   // Resize columns
   outputFlatProfileArea->SetColumnWidth(0, wxLIST_AUTOSIZE_USEHEADER );
   outputFlatProfileArea->SetColumnWidth(1, wxLIST_AUTOSIZE_USEHEADER );
   outputFlatProfileArea->SetColumnWidth(2, wxLIST_AUTOSIZE_USEHEADER );
   outputFlatProfileArea->SetColumnWidth(3, wxLIST_AUTOSIZE_USEHEADER );
   outputFlatProfileArea->SetColumnWidth(4, wxLIST_AUTOSIZE_USEHEADER );
   outputFlatProfileArea->SetColumnWidth(5, wxLIST_AUTOSIZE_USEHEADER );
   outputFlatProfileArea->SetColumnWidth(6, wxLIST_AUTOSIZE);

   // Printing Flat Profile Help
   for ( ; n < msg.GetCount(); n++ )
   {
   	 if (msg[n].Find(0x0C) != -1)
   	     break;
      output_help << msg[n] << _T("\n");
   }
   outputHelpFlatProfileArea->SetValue(output_help);

   return ++n;
}

// This function writes the gprof output to a file
void CBProfilerExecDlg::WriteToFile(wxCommandEvent& event)
{
	size_t n;
	wxFileDialog filedialog(parent, _("Save gprof output to file"),_T(""),_T(""),_T("*.*"),wxSAVE);

	if (filedialog.ShowModal() == wxID_OK)
	{
		wxFFile file(filedialog.GetPath().c_str(), _T("w"));
		for (n=0; n<gprof_output.GetCount(); n++)
		{
		   file.Write(gprof_output[n]);
		   file.Write(_T("\n"));
		}
		file.Close();
	}
}


syntax highlighted by Code2HTML, v. 0.9.1