	/****************************************************************/
	/* EESchema: find.cpp (functions for seraching a schematic item */
	/****************************************************************/
/*
	Search a text (text, value, reference) withing e composent or
	search a composant in libraries, a marker ...,
	in current sheet or whole the project
*/
#include "fctsys.h"
#include "gr_basic.h"

#include "common.h"
#include "program.h"
#include "libcmp.h"
#include "general.h"

/* Variables Locales */
static int s_ItemsCount, s_MarkerCount;
static wxString s_OldStringFound;

#include "dialog_find.cpp"


#include "protos.h"



/**************************************************************/
void InstallFindFrame(WinEDA_SchematicFrame *parent, wxPoint & pos)
/**************************************************************/
{
	parent->DrawPanel->m_IgnoreMouseEvents = TRUE;
	WinEDA_FindFrame * frame = new WinEDA_FindFrame(parent);
	frame->ShowModal(); frame->Destroy();
	parent->DrawPanel->m_IgnoreMouseEvents = FALSE;
}


/**************************************************************/
void WinEDA_FindFrame::FindMarker(wxCommandEvent& event)
/**************************************************************/
/*  Search de markers in whole the hierarchy.
	Mouse cursor is put on the marker
	search the first marker, or next marker
*/
{
int id = event.GetId();
	if( id != FIND_NEXT_MARKER ) m_Parent->FindMarker(0);
	else m_Parent->FindMarker(1);

	Close();
	
}
/*****************************************************************/
EDA_BaseStruct * WinEDA_SchematicFrame::FindMarker(int SearchType)
/*****************************************************************/
/* Search markers in whole the hierarchy.
	Mouse cursor is put on the marker
	SearchType = 0: search the first marker, else search next marker
*/
{
SCH_SCREEN * Screen, * FirstScreen = NULL;
EDA_BaseStruct *DrawList, *FirstStruct = NULL, *Struct = NULL;
DrawMarkerStruct * Marker = NULL;
int StartCount;
bool NotFound;
wxPoint firstpos, pos;
wxSize size = DrawPanel->GetClientSize();
wxPoint curpos, old_cursor_position;
bool force_recadre = FALSE;
wxString msg, WildText;
	
	g_LastSearchIsMarker = TRUE;
	/* Set s_MarkerCount to 0 if we are look for the first marker */
	if( SearchType == 0 ) s_MarkerCount = 0;

	EDA_ScreenList ScreenList(NULL);
	NotFound = TRUE; StartCount = 0;
	/* Search for s_MarkerCount markers */
	for ( Screen = ScreenList.GetFirst(); Screen != NULL; Screen = ScreenList.GetNext() )
	{
		DrawList = Screen->EEDrawList;
		while ( DrawList && NotFound )
		{
			if(DrawList->m_StructType == DRAW_MARKER_STRUCT_TYPE )
			{
			Marker = (DrawMarkerStruct *) DrawList;
				NotFound = FALSE;
				pos = Marker->m_Pos;
				if ( FirstScreen == NULL )	/* First item found */
				{
					FirstScreen = Screen; firstpos = pos;
					FirstStruct = DrawList;
				}
	
				StartCount++;
				if( s_MarkerCount >= StartCount )
				{
					NotFound = TRUE;	/* Search for other markers */
				}
				else	/* We have found s_MarkerCount markers -> Ok */
				{
					Struct = DrawList; s_MarkerCount++; break ;
				}
			}
			DrawList = DrawList->Pnext;
		}
		if( NotFound == FALSE ) break;
	}
	
	if( NotFound && FirstScreen )	// markers are found, but we have reach the last marker */
	{	// After the last marker, the first marker is used */
		NotFound = FALSE; Screen = FirstScreen;
		Struct = FirstStruct;
		pos = firstpos; s_MarkerCount = 1;
	}

	if( NotFound == FALSE)
	{
		if ( Screen != GetScreen() )
		{
			Screen->SetZoom(GetScreen()->GetZoom() );
			m_CurrentScreen = ActiveScreen = Screen;
			force_recadre = TRUE;
		}

		old_cursor_position = Screen->m_Curseur;
		Screen->m_Curseur = pos;
		curpos = DrawPanel->CursorScreenPosition();
		// calcul des coord curseur avec origine = screen
		DrawPanel->GetViewStart(&m_CurrentScreen->m_StartVisu.x,
								&m_CurrentScreen->m_StartVisu.y);
		curpos.x -= m_CurrentScreen->m_StartVisu.x;
		curpos.y -= m_CurrentScreen->m_StartVisu.y;

		/* Il y a peut-etre necessite de recadrer le dessin: */
		if( (curpos.x <= 0) || (curpos.x >= size.x-1) ||
			(curpos.y <= 0) || (curpos.y >= size.y) || force_recadre )
		{
			Recadre_Trace(TRUE);
		}
		else
		{
			wxClientDC dc(DrawPanel);
			DrawPanel->PrepareGraphicContext(&dc);
			EXCHG(old_cursor_position, Screen->m_Curseur);
			DrawPanel->CursorOff(&dc);
 			GRMouseWarp(DrawPanel, curpos );
			EXCHG(old_cursor_position, Screen->m_Curseur);
			DrawPanel->CursorOn(&dc);
 		}

		msg.Printf( _("Marker %d found in %s"), s_MarkerCount, Screen->m_FileName.GetData());
		Affiche_Message(msg);
	}

	else
	{
		Affiche_Message(wxEmptyString);
		msg = _("Marker Not Found");
		DisplayError(this,msg, 10);
	}
	
	return Marker;
}


/**************************************************************/
void WinEDA_FindFrame::FindSchematicItem(wxCommandEvent& event)
/**************************************************************/
/* Find a string in schematic.
	Call to WinEDA_SchematicFrame::FindSchematicItem()
*/
{
int id = event.GetId();

	if( id == FIND_SHEET )
		m_Parent->FindSchematicItem(m_NewTextCtrl->GetValue(), 0);
	else if( id == FIND_HIERARCHY )
		m_Parent->FindSchematicItem(m_NewTextCtrl->GetValue(), 1);
	else if( id == FIND_NEXT )
		m_Parent->FindSchematicItem(wxEmptyString, 2);

	Close();
}

/************************************************************************/
EDA_BaseStruct * WinEDA_SchematicFrame::FindSchematicItem(
			const wxString & pattern, int SearchType)
/************************************************************************/
/* Find a string in schematic.
	Search is made in current sheet (SearchType = 0),
	or the whole hierarchy (SearchType = 1),
	or for the next item  (SearchType = 2).
	Mouse cursor is put on item
*/
{
SCH_SCREEN * Screen, * FirstScreen = NULL;
EDA_BaseStruct *DrawList = NULL, *FirstStruct = NULL, *Struct = NULL;
int StartCount, ii, jj;
bool NotFound;
wxPoint firstpos, pos, old_cursor_position;
static int Find_in_hierarchy;
wxSize size = DrawPanel->GetClientSize();
wxPoint curpos;
bool force_recadre = FALSE;
wxString msg, WildText;
	
	g_LastSearchIsMarker = FALSE;
	
	if( SearchType == 0 )
	{
		s_OldStringFound = pattern;
		Find_in_hierarchy = FALSE;
	}
	
	if( SearchType == 1 )
	{
		s_OldStringFound = pattern;
		Find_in_hierarchy = TRUE;
	}

	if(  SearchType != 2  ) s_ItemsCount = 0;

	WildText = s_OldStringFound;
	NotFound = TRUE; StartCount = 0;
	
	EDA_ScreenList ScreenList(NULL);
	Screen = ScreenList.GetFirst();
	if ( ! Find_in_hierarchy )  Screen = (SCH_SCREEN*) m_CurrentScreen; 

	for ( ; Screen != NULL; Screen = ScreenList.GetNext() )
	{
		DrawList = Screen->EEDrawList;
		while ( DrawList )
		{
			switch (DrawList->m_StructType)
			{
				case DRAW_LIB_ITEM_STRUCT_TYPE :
					#undef STRUCT
					#define STRUCT ((EDA_SchComponentStruct*)DrawList)
					if( WildCompareString( WildText, STRUCT->m_Field[REFERENCE].m_Text, FALSE ) )
					{
						NotFound = FALSE;
						pos = STRUCT->m_Field[REFERENCE].m_Pos;
						break;
					}
					if( WildCompareString( WildText, STRUCT->m_Field[VALUE].m_Text, FALSE ) )
					{
						NotFound = FALSE;
						pos = STRUCT->m_Field[VALUE].m_Pos;
					}
					break;

				case DRAW_LABEL_STRUCT_TYPE :
				case DRAW_GLOBAL_LABEL_STRUCT_TYPE :
				case DRAW_TEXT_STRUCT_TYPE :
					#undef STRUCT
					#define STRUCT ((DrawTextStruct*)DrawList)
					if( WildCompareString( WildText, STRUCT->m_Text, FALSE ) )
					{
						NotFound = FALSE;
						pos = STRUCT->m_Pos;
					}
					break;

				default:
					break;
			}

			if(NotFound == FALSE)	/* Element trouve */
			{
				if ( FirstScreen == NULL )	/* 1er element trouve */
				{
					FirstScreen = Screen; firstpos = pos;
					FirstStruct = DrawList;
				}

				StartCount++;
				if( s_ItemsCount >= StartCount )
				{
					NotFound = TRUE;	/* Continue recherche de l'element suivant */
				}
				else
				{
					Struct = DrawList; s_ItemsCount++; break ;
				}
			}
			if( NotFound == FALSE ) break;
			DrawList = DrawList->Pnext;
		}
		if( NotFound == FALSE ) break;
		if( Find_in_hierarchy == FALSE ) break;
	}

	if( NotFound && FirstScreen )
	{
		NotFound = FALSE; Screen = FirstScreen; Struct = FirstStruct;
		pos = firstpos; s_ItemsCount = 1;
	}

	if( NotFound == FALSE)
	{
		if ( Screen != GetScreen() )
		{
			Screen->SetZoom(GetScreen()->GetZoom() );
			m_CurrentScreen = ActiveScreen = Screen;
			force_recadre = TRUE;
		}

		/* Si la struct localisee est du type DRAW_LIB_ITEM_STRUCT_TYPE,
			Les coordonnes sont a recalculer en fonction de la matrice
			d'orientation */
		if( Struct->m_StructType == DRAW_LIB_ITEM_STRUCT_TYPE )
		{
			#undef STRUCT
			#define STRUCT ((EDA_SchComponentStruct*)Struct)
			pos.x -= STRUCT->m_Pos.x; pos.y -= STRUCT->m_Pos.y;
			ii = STRUCT->m_Transform[0][0] * pos.x + STRUCT->m_Transform[0][1] * pos.y;
			jj = STRUCT->m_Transform[1][0] * pos.x + STRUCT->m_Transform[1][1] * pos.y;
			pos.x = ii + STRUCT->m_Pos.x; pos.y = jj + STRUCT->m_Pos.y;
		}

		old_cursor_position = Screen->m_Curseur;
		Screen->m_Curseur = pos;
		curpos = DrawPanel->CursorScreenPosition();
		DrawPanel->GetViewStart(&m_CurrentScreen->m_StartVisu.x,
								&m_CurrentScreen->m_StartVisu.y);

		// calcul des coord curseur avec origine = screen
		curpos.x -= m_CurrentScreen->m_StartVisu.x;
		curpos.y -= m_CurrentScreen->m_StartVisu.y;

		/* Il y a peut-etre necessite de recadrer le dessin: */
		if( (curpos.x <= 0) || (curpos.x >= size.x-1) ||
			(curpos.y <= 0) || (curpos.y >= size.y) || force_recadre )
		{
			Recadre_Trace(TRUE);
		}
		else
		{
			wxClientDC dc(DrawPanel);
			DrawPanel->PrepareGraphicContext(&dc);
			EXCHG(old_cursor_position, Screen->m_Curseur);
			DrawPanel->CursorOff(&dc);
 			GRMouseWarp(DrawPanel, curpos );
			EXCHG(old_cursor_position, Screen->m_Curseur);
			DrawPanel->CursorOn(&dc);
		}

		msg = WildText + _(" Found in ") + Screen->m_FileName;
		Affiche_Message(msg);
	}

	else
	{
		Affiche_Message(wxEmptyString);
		msg = WildText + _(" Not Found");
		DisplayError(this,msg, 10);
	}
	
	return DrawList;
}


/*************************************************************/
void WinEDA_FindFrame::LocatePartInLibs(wxCommandEvent& event)
/*************************************************************/
/* Recherche exhaustive d'un composant en librairies, meme non chargees
*/
{
wxString Text, FindList;
const wxChar ** ListNames;
LibraryStruct *Lib = NULL;
EDA_LibComponentStruct * LibEntry;
bool FoundInLib = FALSE;	// True si reference trouvee ailleurs qu'en cache
	
	Text = m_NewTextCtrl->GetValue();
	if ( Text.IsEmpty() )
	{
		Close(); return;
	}
	s_OldStringFound = Text;

	int ii, nbitems, NumOfLibs = NumOfLibraries();
	if (NumOfLibs == 0)
		{
		DisplayError(this, _("No libraries are loaded"));
		Close(); return;
		}

	ListNames = GetLibNames();
		
	nbitems = 0;
	for (ii = 0; ii < NumOfLibs; ii++ )	/* Recherche de la librairie */
	{
	bool IsLibCache;
		Lib = FindLibrary(ListNames[ii]);
		if ( Lib == NULL ) break;
		if ( Lib->m_Name.Contains( wxT(".cache")) ) IsLibCache = TRUE;
		else IsLibCache = FALSE;
		LibEntry = (EDA_LibComponentStruct *) PQFirst(&Lib->m_Entries, FALSE);
		while( LibEntry )
		{
			if( WildCompareString(Text, LibEntry->m_Name.m_Text, FALSE) )
			{
				nbitems ++;
				if ( ! IsLibCache ) FoundInLib = TRUE;
				if ( ! FindList.IsEmpty() ) FindList += wxT("\n");
				FindList << _("Found ")
						+ LibEntry->m_Name.m_Text
						+ _(" in lib ") + Lib->m_Name;
			}
		LibEntry = (EDA_LibComponentStruct *) PQNext(Lib->m_Entries, LibEntry, NULL);
		}
	}

	free (ListNames);
	
	if ( ! FoundInLib )
	{
		if ( nbitems ) FindList = wxT("\n") + Text + _(" found only in cache");
		else FindList = Text + _(" not found");
		FindList += _("\nExplore All Libraries?");
		if ( IsOK(this, FindList) )
		{
			FindList.Empty();
			ExploreAllLibraries(Text, FindList);
			if ( FindList.IsEmpty() ) DisplayInfo(this, _("Nothing found") );
			else DisplayInfo(this, FindList);
		}
	}
	else DisplayInfo(this, FindList);
	
	Close();
}


/***************************************************************************************/
int WinEDA_FindFrame::ExploreAllLibraries(const wxString & wildmask, wxString & FindList)
/***************************************************************************************/
{
wxString FullFileName;
FILE * file;
int nbitems = 0, LineNum = 0;
char Line[2048], *name;
	
	FullFileName = MakeFileName(g_RealLibDirBuffer, wxT("*"), g_LibExtBuffer);
	
	FullFileName = wxFindFirstFile(FullFileName);
	while ( ! FullFileName.IsEmpty() )
	{
		file = wxFopen(FullFileName, wxT("rt"));
		if (file == NULL) continue;
 
		while (GetLine(file, Line, &LineNum, sizeof(Line)) )
		{
			if (strnicmp(Line, "DEF", 3) == 0)
			{ /* Read one DEF part from library: DEF 74LS00 U 0 30 Y Y 4 0 N */
				strtok(Line, " \t\r\n");
				name = strtok(NULL, " \t\r\n");
				wxString st_name = CONV_FROM_UTF8(name);
				if( WildCompareString(wildmask, st_name, FALSE) )
				{
					nbitems ++;
					if ( ! FindList.IsEmpty() ) FindList += wxT("\n");
					FindList << _("Found ") << CONV_FROM_UTF8(name)
							<< _(" in lib ") << FullFileName;
				}
			}
			else if (strnicmp(Line, "ALIAS", 5) == 0)
			{ /* Read one ALIAS part from library: ALIAS 74HC00 74HCT00 7400 74LS37 */
				strtok(Line, " \t\r\n");
				while ( (name = strtok(NULL, " \t\r\n")) != NULL )
				{
					wxString st_name = CONV_FROM_UTF8(name);
					if( WildCompareString( wildmask, st_name, FALSE) )
					{
						nbitems ++;
						if ( ! FindList.IsEmpty() ) FindList += wxT("\n");
						FindList << _("Found ") << CONV_FROM_UTF8(name)
								<< _(" in lib ") << FullFileName;
					}
				}
			}
		}
		fclose(file);
		FullFileName = wxFindNextFile();
	}

	return nbitems;
}

