#include "oohg.ch"
#include "hbclass.ch"
#include "i_windefs.ch"
#include "dSign.ch"
                           
MEMVAR oMain, TitleHeight, BorderHeight, BorderWidth, oStat, Position, oWControl, oCtrlBox, oControlP

// Controls Cargo defines
#define ctNAME			1
#define ctPOSITION	2
#define ctSELECTED	3
#define ctOTHER		4

Procedure Open(c, lMsg, cFileName)          
Local cFormTxt
DEFAULT lMsg TO .T.
	// To avoid movement of controls when double clicking
	If !EMPTY(oMain:Cargo)
		ReleaseControls(oMain:Cargo)
	Endif
	
	If Empty(c)             
		c := GetFile({{"*.fmg","*.fmg"},{"*","*.*"}})	
	Endif                   
	If Empty(c)             
		Return               
	Endif

*	If lMsg
*		WaitWindow("Cargando Fmg... ")
*	Endif
   /* Load form */
   cFormTxt := memoread(c)
	OpenFmg(@cFormTxt, c, lMsg, cFileName)
Return 

Procedure OpenFmg(cForm, c, lMsg, cFileName)
Local i, j, cAfter := "", cLine, oWin, oCtrl, cFormTxt
Local x, y, cName, cType, aItems, lWindow := .F.	//, lNew := .F.
Local lGet

	If lMsg
		WaitWindow("Cargando Fmg... ")
	Endif
	// Nota: Conservar en cForm los tabuladores para que el resultado esté como el usuario lo puso
   cForm := hb_StrReplace(cForm, {chr(13)=>''})
	// Quitamos tabuladores
	cFormTxt := hb_StrReplace(cForm, {CHR(9)=>' '})
	// Convertimos a Array
   cForm := hb_aTokens(cForm, CHR(10))
   cFormTxt := hb_aTokens(cFormTxt, chr(10))
	// Quitamos espacios principio y final
	AEVAL(cFormTxt, {|a,n| cFormTxt[n] := ALLTRIM(a)} )

	// OJO, en caso de estar importando del portapapeles, puede que exista o no una ventana
	// por lo tanto
*	If Hb_IsObject(oMain:Cargo)		// si existe ventana ya creada
*		oWin := oMain:Cargo				// usar esa ventana ????
*	Else
*		oWin := AddWindow(, 200, 200, 400, 300)	// crear ventana nueva ????
*		lNew := .T.
*	Endif

   FOR i := 1 TO LEN(cFormTxt)
      cLine := STRTRAN(cFormTxt[i], ";", "")
		cName := ""

		If hb_AtI("dSign", cLine) > 0 .OR. hb_AtI("David", cLine) > 0
			LOOP
		Endif
		
		If EMPTY(cLine) 
			If !EMPTY(cAfter)
			Else
*				cAfter += cForm[i] + hb_eol()
			Endif
			LOOP
		Endif
		
      If hb_AtI( "DEFINE WINDOW", cLine ) == 1
*			If lNew
				// Destroy previusly made window
*				oWin:Release()
*				oWin := NIL
*			Endif
*			cBefore := cAfter
			cType := "WINDOW"
			cName := HB_aTokens(cLine)[3]
			i := GetControlLines(cFormTxt, i, @cLine)
			oWin := ParseControlData(cType, cName, x, y, cLine)

			oWin:cFileName := If(EMPTY(cFileName), c, cFileName)
			oWin:Title := Comillas(oWin:aDatas[wTITLE,2]) + "     ("+oWin:cFileName+")"
			oWin:cBefore := cAfter
			cAfter := ""
*			oMain:Cargo := oWin
			lWindow := .T.

		ElseIf !lWindow
			cAfter := cForm[i] + hb_eol()

      ElseIf  hb_AtI( "END WINDOW", cLine ) == 1
			oWin:cAfter := cAfter
			cAfter := ''
			i++
			EXIT
			
      ElseIf  hb_AtI( "END STATUSBAR", cLine ) == 1
	      _EndMessageBar()
	
      ElseIf  hb_AtI( "END SPLITBOX", cLine ) == 1
	      _EndSplitBox()
	
      ElseIf  hb_AtI( "END TAB", cLine ) == 1
			END TAB

      ElseIf  hb_AtI( "END TREE", cLine ) == 1
			_OOHG_ActiveTree:cAfter := cAfter
			cAfter := ""
			If HB_IsObject(_OOHG_ActiveTree)
				_EndTree()
			Endif
			
      ElseIf  hb_AtI( "END NODE", cLine ) == 1
			_OOHG_ActiveTree:EndNode(cAfter)
			cAfter := ""
			If HB_IsObject(_OOHG_ActiveTree)
				_EndTreeNode()
			Endif
			
      ElseIf  hb_AtI( "END PAGE", cLine ) == 1
			END PAGE
		
      ElseIf  hb_AtI( "END TOOLBAR", cLine ) == 1
			_EndToolBar( .T. )
		
      ElseIf  hb_AtI( "END MENU", cLine ) == 1 .OR. hb_AtI( "END POPUP", cLine ) == 1
			cAfter += cForm[i] + hb_eol()
		
		ElseIf  hb_AtI( "END ", cLine) = 1
			// Used for END LABEL; TEXTBOX; GRID, etc
			
      ElseIf  hb_AtI( "DEFINE PAGE", cLine ) == 1 .OR.  hb_AtI( "PAGE", cLine ) == 1 .OR.  hb_AtI( "DEFINE TAB PAGE", cLine ) == 1
			cType := "PAGE"
			cName := STRTRAN(STRTRAN(SUBSTR(cLine,  hb_AtI("PAGE",cLine)+5), '"',''), "'","")
			i := GetControlLines(cFormTxt, i, @cLine)
			oCtrl := ParseControlData(cType, cName, x, y, cLine, oWin)
			oCtrl:cBefore := cAfter
			cAfter := ""

      ELSEIF  hb_AtI( "STATUSITEM", cLine ) == 1 .OR. hb_AtI( "KEYBOARD", cLine ) == 1 ;
					.OR. hb_AtI( "DATE", cLine ) == 1 .OR. hb_AtI( "CLOCK", cLine ) == 1
*			cType := "STATUSITEM"
			i := GetControlLines(cFormTxt, i, @cLine)
			// Search for StatusBar to save in Cargo StatusItem Datas
			// oCtrl (last control made) should be it
			// Need to save Action, Style
			If oCtrl:Type == "MESSAGEBAR" 
				j := 1
				WHILE !EMPTY(cLine)
					aItems := {"",,,"","","",, .F. }	//Caption, Width, action, ToolTip, icon, Style, Align, lDefault
					If cLine[j] = "STATUSITEM"
						Hb_aDel(cLine, j, .T.)
						aItems[1] := cLine[j]
						Hb_aDel(cLine, j, .T.)
					ElseIf cLine[j] = "CLOCK"
						aItems[1] := cLine[j]
						Hb_aDel(cLine, j, .T.)
					ElseIf cLine[j] = "KEYBOARD"
						aItems[1] := cLine[j]
						Hb_aDel(cLine, j, .T.)
					ElseIf cLine[j] = "DATE"
						aItems[1] := cLine[j]
						Hb_aDel(cLine, j, .T.)
					Endif

					If !EMPTY(cLine) .AND. cLine[j] = "WIDTH"
						Hb_aDel(cLine, j, .T.)
						aItems[2] := VAL(cLine[j])
						Hb_aDel(cLine, j, .T.)
					ENDIF
					If !EMPTY(cLine) .AND. cLine[j] = "ACTION"
						Hb_aDel(cLine, j, .T.)
						aItems[3] := cLine[j]
						Hb_aDel(cLine, j, .T.)
					Endif
					If !EMPTY(cLine) .AND. cLine[j] = "TOOLTIP"
						Hb_aDel(cLine, j, .T.)
						aItems[4] := cLine[j]
						Hb_aDel(cLine, j, .T.)
					Endif
					If !EMPTY(cLine) .AND. cLine[j] = "ICON"
						Hb_aDel(cLine, j, .T.)
						aItems[5] := cLine[j]
						Hb_aDel(cLine, j, .T.)
					Endif
					If !EMPTY(cLine) .AND. cLine[j] $ "RAISED FLAT"
						aItems[6] := cLine[j]
						Hb_aDel(cLine, j, .T.)
					Endif
					If !EMPTY(cLine) .AND. cLine[j] $ "RIGHT CENTER LEFT"
						aItems[7] := cLine[j]
						Hb_aDel(cLine, j, .T.)
					Endif
					If !EMPTY(cLine) .AND. cLine[j] = "DEFAULT"
						aItems[8] := .T.
						Hb_aDel(cLine, j, .T.)
					Endif
					oCtrl:MyAddItem( aItems )
				Enddo
			Else
				MsgStop("oCtrl no es statusbar")
			Endif
			
		ELSEIF  hb_AtI( "DEFINE MAIN", cLine ) == 1 
			cAfter += cForm[i] + hb_eol()

		ELSEIF  hb_AtI( "DEFINE NOTIFY", cLine ) == 1 
			cAfter += cForm[i] + hb_eol()
		ELSEIF  hb_AtI( "DEFINE HOTKEY", cLine ) == 1 
			cAfter += cForm[i] + hb_eol()
*		ELSEIF  hb_AtI( "POPUP", cLine ) == 1 
*			cAfter += cForm[i] + hb_eol()
*		ELSEIF  hb_AtI( "ITEM", cLine ) == 1 
*			cAfter += cForm[i] + hb_eol()
		
		ELSEIF  hb_AtI( "DEFINE STATUSBAR", cLine ) == 1 
			cType := "STATUSBAR"
			i := GetControlLines(cFormTxt, i, @cLine)
			oCtrl := ParseControlData(cType, cName, x, y, cLine, oWin)
			oCtrl:cBefore := cAfter
			cAfter := ""
			
		ELSEIF  hb_AtI( "DEFINE SPLITBOX", cLine ) == 1 
			cType := "SPLITBOX"
			i := GetControlLines(cFormTxt, i, @cLine)
			oCtrl := ParseControlData(cType, cName, x, y, cLine, oWin)
			oCtrl:cBefore := cAfter
			cAfter := ""

      ELSEIF  hb_AtI( "DEFINE TAB", cLine ) == 1
			cType := "TAB"
			cName := Hb_aTokens(cLine)[3]
			i := GetControlLines(cFormTxt, i, @cLine)
			oCtrl := ParseControlData(cType, cName, x, y, cLine, oWin)
			oCtrl:cBefore := cAfter
			cAfter := ""
			
      ELSEIF  hb_AtI( "DEFINE TIMER", cLine ) == 1
			cType := "TIMER"
			cName := Hb_aTokens(cLine)[3]
			// TIMER DOES NOT HAVE COORDINATES
/*			cLine := ALLTRIM(STRTRAN(cFormTxt[i-1], ";", ""))	// coordinates are in previuos line
			If !EMPTY(cLine)
				cLine := ALLTRIM(STRTRAN(cLine, "*", ""))				// get rid of *
				cLine := HB_aTokens(cLine)
				x := VAL(cLine[2])
				y := VAL(cLine[3])
			Endif
*/
			i := GetControlLines(cFormTxt, i, @cLine)
			oCtrl := ParseControlData(cType, cName, x, y, cLine, oWin)
			oCtrl:cBefore := cAfter
			cAfter := ""

      ELSEIF  hb_AtI( "DEFINE TOOLBAR", cLine ) == 1		
			cType := "TOOLBAR"
			cName := HB_aTokens(cLine)[3]
			i := GetControlLines(cFormTxt, i, @cLine)
			oCtrl := ParseControlData(cType, cName, x, y, cLine, oWin)
			oCtrl:cBefore := cAfter
			cAfter := ""

      ELSEIF  hb_AtI( "DEFINE TREE", cLine ) == 1
			cType := "TREE"
//			cName := TRIM(SUBSTR(cLine,  hb_AtI("TREE",cLine)+5))
			cName := HB_aTokens(cLine)[3]

			i := GetControlLines(cFormTxt, i, @cLine)
			oCtrl := ParseControlData(cType, cName, x, y, cLine, oWin)
			oCtrl:cBefore := cAfter
			cAfter := ""
			
		ELSEIF  hb_AtI( "TREEITEM", cLine ) == 1
*			cType := "TREEITEM"
			i := GetControlLines(cFormTxt, i, @cLine)
//_DefineTreeItem( text, aImage, Id, lChecked, lReadOnly, lBold, lDisabled, lNoDrag, lAssignID )
			j := 1
			aItems := {"",,,,,,,, }	//text, aImage, Id, lChecked, lReadOnly, lBold, lDisabled, lNoDrag, lAssignID
			WHILE !EMPTY(cLine)

				If !EMPTY(cLine) .AND. cLine[j] = "IMAGES"
					Hb_aDel(cLine, j, .T.)
					aItems[2] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "ID"
					Hb_aDel(cLine, j, .T.)
					aItems[3] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "CHECKED"
					Hb_aDel(cLine, j, .T.)
					aItems[4] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "READONLY"
					Hb_aDel(cLine, j, .T.)
					aItems[5] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "BOLD"
					Hb_aDel(cLine, j, .T.)
					aItems[6] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "DISABLED"
					Hb_aDel(cLine, j, .T.)
					aItems[7] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "NODRAG"
					Hb_aDel(cLine, j, .T.)
					aItems[8] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "AUTOID"
					Hb_aDel(cLine, j, .T.)
					aItems[9] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ELSEIF !EMPTY(cLine)
					If cLine[j] == "TREEITEM"
						Hb_aDel(cLine, j, .T.)
					Endif
					
					aItems[1] += cLine[j]
					Hb_aDel(cLine, j, .T.)
				ENDIF
			ENDDO
			_OOHG_ActiveTree:AddItem( "TREEITEM", cAfter, aItems[1], aItems[2], aItems[3], aItems[4], aItems[5], aItems[6], aItems[7], aItems[8], aItems[9] )
			cAfter := ""

		ELSEIF  hb_AtI( "DEFINE NODE", cLine ) == 1 .OR. hb_AtI( "NODE", cLine ) == 1
*			cType := "NODE"
			i := GetControlLines(cFormTxt, i, @cLine)
//_DefineTreeNode( text, aImage, Id, lChecked, lReadOnly, lBold, lDisabled, lNoDrag, lAssignID )
			j := 1
			aItems := {"",,,,,,,, }	//text, aImage, Id, lChecked, lReadOnly, lBold, lDisabled, lNoDrag, lAssignID
			WHILE !EMPTY(cLine)

				If !EMPTY(cLine) .AND. cLine[j] = "IMAGES"
					Hb_aDel(cLine, j, .T.)
					aItems[2] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "ID"
					Hb_aDel(cLine, j, .T.)
					aItems[3] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "CHECKED"
					Hb_aDel(cLine, j, .T.)
					aItems[4] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "READONLY"
					Hb_aDel(cLine, j, .T.)
					aItems[5] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "BOLD"
					Hb_aDel(cLine, j, .T.)
					aItems[6] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "DISABLED"
					Hb_aDel(cLine, j, .T.)
					aItems[7] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "NODRAG"
					Hb_aDel(cLine, j, .T.)
					aItems[8] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ENDIF
				If !EMPTY(cLine) .AND. cLine[j] = "AUTOID"
					Hb_aDel(cLine, j, .T.)
					aItems[9] := VAL(cLine[j])
					Hb_aDel(cLine, j, .T.)
				ELSEIF !EMPTY(cLine)
					If cLine[j] == "NODE"
						Hb_aDel(cLine, j, .T.)
					Endif
					aItems[1] += cLine[j]
					Hb_aDel(cLine, j, .T.)
				ENDIF
			ENDDO

			_OOHG_ActiveTree:AddItem( "NODE", cAfter, aItems[1], aItems[2], aItems[3], aItems[4], aItems[5], aItems[6], aItems[7], aItems[8], aItems[9] )
			cAfter := ""
		
      ELSEIF  hb_AtI( "DEFINE", cLine ) == 1		// This is for DEFINE LABEL, TEXTBOX, GRID, etc
			cType := HB_aTokens(cLine)[2]
			cName := HB_aTokens(cLine)[3]
			// next row is ROW and next y COL  // Not true, could be OBJECT
			 
			i := GetOldControlLines(cFormTxt, ++i, @cLine)
//db_Text(cLine)
			If UPPER(LEFT(ATAIL(cLine),2)) == "END"
				// Delete last line that has END ...
				hb_aDel(cLine, LEN(cLine), .T.)
			Endif
			// Get ROW
			If (j := ASCAN(cLine, {|a| UPPER(LEFT(a,3)) == "ROW"})) > 0
//db_Text("Row ="+SUBSTR(cLine[j],4))
				x := VAL(SUBSTR(cLine[j],4))
				hb_aDel(cLine, j, .T.)
			Endif
			// Get COL
			If (j := ASCAN(cLine, {|a| UPPER(LEFT(a,3)) == "COL"})) > 0
				y := VAL(SUBSTR(cLine[j],4))
				hb_aDel(cLine, j, .T.)
			Endif
			oCtrl := ParseControlData(cType, cName, x, y, cLine, oWin, .T.)
			oCtrl:cBefore := cAfter
			cAfter := ""
			
      ELSEIF (  hb_AtI( "BUTTON", cLine ) == 1 )	// Botones del ToolBar
			cType := "TBUTTON"
			cName := HB_aTokens(cLine)[2]
			i := GetControlLines(cFormTxt, i, @cLine)
			oCtrl := ParseControlData(cType, cName, x, y, cLine, oWin)
			oCtrl:cBefore := cAfter
			cAfter := ""
			
      ELSEIF (  hb_AtI( "@", cLine ) == 1 )		// Controles @ x,y ...
         /* Control */
			// Hay veces que ponen @001,002 ...
			// Separar @ de lo demás
			If hb_AT("@ ", cLine) = 0
				cLine := STRTRAN(cLine, "@", "@ ")
			Endif
			cLine := STRTRAN(cLine, ",", ", ")	// Cambiar comas juntas al texto (,xxx) a comas separadas del texto (, xxx)
			cLine := HB_aTokens(cLine)				// Crear arreglo con tokens por espacios  
			x := VAL(cLine[2])
			y := VAL(cLine[3])
			cType := UPPER(cLine[4])
			cName := cLine[5]

			i := GetControlLines(cFormTxt, i, @cLine)
//If cType == "TEXTBOX"
*	lGet := (HB_ASCAN(cLine, {|a| UPPER(a) =="GET"} ) > 0)
	lGet := ("DAVID-I712" $ UPPER(NETNAME()))
//Endif

			oCtrl := ParseControlData(cType, cName, x, y, cLine, oWin)
			
			If hb_IsObject(oCtrl)
				oCtrl:Cargo[6] := lGet
				oCtrl:cBefore := cAfter
				cAfter := ""
			Endif

		Else
			If  hb_AtI( "*****@", cLine ) == 1		// Don't save @ TIMER
			Else
				cAfter += cForm[i]+ hb_eol()
			Endif
      ENDIF

   NEXT i
	cAfter := ""
	For j := i TO LEN(cFormTxt)	// Guardar todo lo que hayan puesto despues del END WINDOW
		cAfter += cForm[j] + hb_eol()
	Next
	cAfter := STRTRAN(cAfter, HB_EOL()+HB_EOL(), HB_EOL())
	RestofFMG := cAfter
	If lMsg
		CloseWait()
	Endif
	
	If HB_IsObject(oWin) .AND. !oWin:Active
		oWin:Activate(.T.)
	Endif
	UpdateWControls(oWin)
	oWControl:Show()
Return

// This function reads all lines af control definition and creates array cLine with each
Function GetControlLines(cFormTxt, i, cLine, lMakeArray)
Local j, xTemp, lNext := .T., xTemp1	//, n
DEFAULT lMakeArray TO .T.

	j := i
	xTemp := ""
	While lNext 
		xTemp1 := ALLTRIM(cFormTxt[j])
*		If (n := Hb_At("//", xTemp1, Hb_At(";", xTemp1)) ) > 0		// descartar lineas de comentarios entre la definicion
// Aquí existe la posibilidad de agregar el comentario en algún lado (???)
*			xTemp1 := LEFT(xTemp1, n-1)
*		Endif

		If j <> i .AND. LEFT(xTemp1,1) <> " "  // Agregar espacio por si no existe
			xTemp += " "
		Endif

		xTemp += STRTRAN(xTemp1, ";" , "")	// Add to xTemp line contents replacing ; with blank
*		If RIGHT(xTemp1,1) <> ";"				// If last caracther is not ; we have reached end of definition
		If Hb_At(";", xTemp1) = 0				// If last caracther is not ; we have reached end of definition
//db_Text("'"+xTemp1+"'")
			lNext := .F.
		Endif
		If lNext //.OR. i <> j												// Increment only if more than 1 line
			j ++
		Endif
	Enddo
   cLine := hb_StrReplace(xTemp, {chr(10) => " ",;		// Remove CHR(10)
;//												" -" => "-",;
;//												" +" => "+",;
;//												" *" => "*",;
;//												" /" => "/",;
;//												"- " => "-",;
;//												"+ " => "+",;
;//												"* " => "*",;
;//												"/ " => "/",;
;//												" , " => ",",;		// Remove space between comas
												", " => ",",;		// Remove space between comas
												" ," => ",",;		// Remove space between comas OJO quizá no hacerlo, es para los casos AT 100, 200
												" ON " => " ON",;	// Remove space between ON CLICK, etc
												" on " => " ON";
;//												"{ " => "{", ;		// Remove space between { 0,255,255 }
;//												" }" => "}" ,;		// and end of blocks
;//												"{|| " => "{||" ;	// Remove spaces from beginig of blocks
												} )			
//db_Text(cLine)
	If lMakeArray
		cLine := MakeArray(cLine)
	Endif
// db_Text(cLine)	
Return j

Function GetOldControlLines(cFormTxt, i, cLine, cEnd)
Local j, xTemp, aRange := {'',''}
DEFAULT cEnd TO "END "
	cLine := {}
	j := i
//	While !EMPTY(cFormTxt[j])
	While .T.
		xTemp := ALLTRIM(STRTRAN(cFormTxt[j], ";" , ""))
		xTemp := If(LEFT(xTemp,3)=="ON ", LEFT(xTemp,2)+SUBST(xTemp,4),xTemp)	// Change ON CLICK to ONCLICK etc.
		If Right(xTemp,1) == ','
			j++
			LOOP
		Endif
		aRange[1] := if( LEFT(xTemp,8)== "RANGEMIN", SUBST(xTemp,9), aRange[1])
		aRange[2] := if( LEFT(xTemp,8)== "RANGEMAX", SUBST(xTemp,9), aRange[2])
		If LEFT(xTemp,5) == "RANGE"
			j++
			LOOP
		Endif
		
		If LEFT(ALLTRIM(cFormTxt[j]),4) == cEnd
			J++
			Exit
		Endif
		AADD(cLine, xTemp )
		J++
	Enddo
	If !EMPTY(aRange[1])
		AADD(cLine, "RANGE "+aRange[1]+","+aRange[2])
	Endif
Return j


Procedure ShowError(oErr, cType, cName, c, aDatas, bError)
	MsgStop("Error en lectura de control "+cType+" '"+cName+"'"+hb_EOL()+HB_DumpVar(c, .T.), "dSign")
//db_Text(hb_DumpVar(aDatas, .T.))	
// db_Text("Error")	
// db_Text("Error en lectura de control "+cType+" "+cName+hb_EOL()+HB_DumpVar(c, .T.))
	EVAL( bError, oErr )
Return 

Function ParseControlData(cType, cName, x, y, c, oWin, lOld)
Local w, h, xTemp, aEvents,  aDatas  
Local i, j, xData, cAfter := "", bError
DEFAULT lOld TO .F.

	aDatas := GetDataArray(cType)
//	DEFAULT aDatas TO SUPPORTED_DATAS
	cType := UPPER(cType)		// Necesario que esté en UPPERCASE
	If !lOld
		c := PreProcessControl( c, aDatas )
//db_Text(cType+" "+cName)
//db_Text(c)
	Endif
	aEvents := aDatas[2]
	aDatas  := aDatas[1]

	bError := ErrorBlock()
	bError := ErrorBlock( {| oErr | ShowError( oErr, cType, cName, c, aDatas, bError ) } )
	
//BEGIN SEQUENCE //WITH {| oErr | ShowError( oErr, cType, cName, c ) }
	aDatas[NAME,2] := cName
	For i := 1 TO LEN(c)
		If ( hb_AtI( "DEFINE", c[i] ) == 1)				// ignorar DEFINE's
			Loop
		Endif
*		If LEFT(c[i],3) == "ON "						// Quitar el espacio entre el ON y la accion
*			c[i] := LEFT(c[i],2)+SUBSTR(c[i],4)
*		Endif
		// particionar cada elemento del array c en DEFINICION y su contraparte
		xTemp := UPPER(hb_aTokens(c[i], " ")[1])	//SUBSTR(c[i], 1 , AT(" ", c[i])-1)
		xData := ALLTRIM(SUBSTR(c[i], LEN(xTemp)+1))

		j := ASCAN(aDatas, {|a| a[1] == xTemp} )
		If j = 0		// Buscar en las opciones alternativas
			j := Data_Options(@xTemp)
		Endif

		If j> 0
			If Hb_IsLogical(aDatas[j,2])		// Logicals
				If j = dREADONLY
					If TYPE(xData) = 'A'
						aDatas[j,2] := &xData
					Else
						aDatas[j][2] := If(EMPTY(xData), .T., If(xData = '.T.' , .T., .F.))
					Endif
*				ElseIf j = dOOHGDRAW .OR. j = dWINDRAW
					
				Else
					aDatas[j][2] := If(EMPTY(xData), .T., If(xData = '.T.' , .T., .F.))
				Endif

			ElseIf hb_IsNumeric(aDatas[j,2]) .OR. aDatas[j,2] = NIL	//Numeric
				// OJO Puede ser una formula
				aDatas[j,2] := If(IsDigit(xData), VAL(xData), xData)

			ElseIf hb_IsArray(aDatas[j,2]) 
				If LEFT(xData,1) == "{"// Arrays
					If xTemp == "JUSTIFY" 
						// Convertir BROWSE_JTFY_RIGHT, BROWSE_JTFY_LEFT, BROWSE_JTFY_CENTER
						xData := hb_StrReplace( xData, { 'BROWSE_JTFY_RIGHT' => '1', 'BROWSE_JTFY_LEFT' => '0', 'BROWSE_JTFY_CENTER' => '2',;
																	'GRID_JTFY_RIGHT' => '1', 'GRID_JTFY_LEFT' => '0', 'GRID_JTFY_CENTER' => '2',;
																	'XBROWSE_JTFY_RIGHT' => '1', 'XBROWSE_JTFY_LEFT' => '0', 'XBROWSE_JTFY_CENTER' => '2','XBROWSE_JTFY_JUSTIFYMASK' => '3'})
						aDatas[j,2] := &(xData)
					ElseIf xTemp == "HEADERCOLORS"
						If hb_AtI( "|", xData) = 0
							aDatas[j,2] := &(xData)
						ELSEIF hb_AtI( "|", xData) <> 0
							aDatas[j,2] := StrToColor(xData)
						Endif
					Else
*db_Text(xData)
						aDatas[j,2] := &(xData)	//MakeArray(xData)	
*db_Text(aDatas[j,2])
					Endif
				ElseIf !EMPTY(xData)	// Info should be array but is not
					//Case BackColor can be RED, GREEN, etc
					aDatas[j,2] := xData
				Endif
					
			ElseIf UPPER(xData) == "NIL" .OR. xData == '""' 
			Else
/*				If xTemp $ "TITLE VALUE CAPTION"
				Else
					If Left(xData,1) == "'" .or. LEFT(xData,1) = '"'
					// Aqui se quitan las comillas (no se debe) 2021-04-27
*						xData := SUBSTR(xData,2, LEN(xData)-2)
					Endif
				Endif */
//db_Text(xData)
				aDatas[j,2] := xData
			Endif
		Else 
			If LEFT(c[i],2) = "AT" .OR. c[i] == "AT" 
			ElseIf xTemp == "TABSTOP" // Special cases for aDatas
				// This happens only with oldstyle
				aDatas[dNOTABSTOP, 2] := If(xData = '.T.' , .F., .T.)
				
			Else
				// Buscar en eventos
				j := ASCAN(aEvents, {|a| a[1] == xTemp})
				If j = 0									// si no se encuentra
					j := Event_Options(@xTemp)		// Buscar en las opciones alternativas
				Endif
				If j > 0									// encontrado
					aEvents[j,2] := ALLTRIM(SUBSTR(c[i], LEN(xTemp)+1))
				Else	
// de aquí
*					If xTemp == "WIDTH" 
*						w := VAL(xData)
*					ElseIf xTemp == "HEIGHT"
*						h := VAL(xData)
// a acá nunca debería de suceder. ¿¿¿ Por qué tengo esto ????
*					Else // No Encontrado, poner en cAfter
						cAfter += c[i]+" ;"+hb_eol()		// Add to cAfter
*					Endif
				Endif
			Endif
		Endif

		// Caso especial para GRID, BROWSE y XBROWSE donde IMPUTMASK es array
*if xTemp == "INPUTMASK" .AND. cType $ "GRID BROWSE XBROWSE"
*	aDatas[j,2] := &xData
*	msgbox(hb_dumpvar(aDatas[dINPUTMASK,2], .T.),cType)
*Endif
	Next

	If cType $ "WINDOW TREE TAB"
		xTemp := HB_aTokens(GetControlData("AT",c), ",")
		x := VAL(xTemp[1])
		y := VAL(xTemp[2])
	ElseIf cType == "TOOLBAR"
		xData := Hb_aTokens(GetValue("BUTTONSIZE", c), ",")
		w := VAL(xData[1])
		h := VAL(xData[2])
	ElseIf cType == "PAGE"
		aDatas[tpCAPTION, 2] := cName
	Endif
	
	If cType == "STATUSBAR"
		aDatas[stSTYLE,2] := IF(GetValue("RAISED", c, "L") <> NIL, "RAISED", "FLAT")
		aDatas[stALIGN,2] := IF(GetValue("RIGHT", c, "L") <> NIL, "RIGHT", IF(GetValue("CENTER", c, "L") <> NIL, "CENTER", "LEFT"))
	Endif
	
	If cType == "WINDOW"
		w := aDatas[wWIDTH,2]
		h := aDatas[wHEIGHT,2]
		xTemp := AddWindow(cName, x, y, w, h, STRTRAN(GetControlData("TITLE", c), "'", ""), aDatas, cAfter)
		xTemp:aEvents := aEvents
	Else
		If LEN(aDatas) >= 100	// Temporal para que no falle con datas ya creadas por control
			w := aDatas[dWIDTH,2]
			h := aDatas[dHEIGHT,2]
		Endif
		xTemp := AddControl(cType, cName, x, y, w, h, oWin, aDatas, cAfter, .F.)
		xTemp:aEvents := aEvents
	Endif
		
	ErrorBlock( bError)
*RECOVER USING oErr
*	MsgStop("Error en lectura de control "+cType+" "+cName+hb_EOL()+HB_DumpVar(c, .T.), "dSign")
*	EVAL( ErrorBlock(), oErr )
//END
	ErrorBlock( bError)

Return xTemp


Function Data_Options(aData)
Local n := ASCAN( DATA_OPTIONS, {|a| a[1] == aData} )
	If n > 0
		n := DATA_OPTIONS[n,2]
	Endif
Return n

Function Event_Options(aData)
Local n := ASCAN( EVENT_OPTIONS, {|a| a[1] == aData} )
	If n > 0
		n := EVENT_OPTIONS[n,2]
	Endif
Return n

Function GetValue(cItem, cLines, cType)
Local xRet, n
	If (n := ASCAN(cLines, {|a| LEFT(a,LEN(cItem)) == cItem} )) > 0
		xRet := ALLTRIM(SUBSTR(cLines[n], LEN(cItem)+1))
		If cType = "N"
			xRet := VAL(xRet)
		ElseIf cType = "A"
			xRet := &(xRet)
		ElseIf cType = "L"
			If Empty(xRet)
				xRet := .T.
			Else
				xRet := If(xRet = ".T.", .T., .F.)
			Endif
		Else
			If Left(xRet,1) == "'" 
				xRet := STRTRAN(xRet, "'", "")
			ElseIf LEFT(xRet,1) = '"'
				xRet := STRTRAN(xRet, '"', "")
			Endif
		Endif
	Endif
Return xRet
		
Function GetaDatas(cName, aDatas)
Local n := ASCAN(aDatas, {|a| a[1] == cName} )
Return IF(n = 0, NIL, aDatas[n,2])

Procedure PutaDatas(cName, xValue, aDatas)
Local n := ASCAN(aDatas, {|a| a[1] == cName} )
/*	If Hb_IsLogical(aDatas[n,2])
		aDatas[n,2] := If(EMPTY(xValue), .T., If(xValue = '.T.' , .T., .F.))
	ElseIf hb_IsNumeric(aDatas[n,2]) .OR. aDatas[n,2] = NIL
		aDatas[n,2] := VAL(xValue)
	ElseIf hb_IsArray(aDatas[n,2])
		aDatas[n,2] := &(xValue)
	ElseIf UPPER(xValue) == "NIL" .OR. xValue == '""' 
	Else
		If Left(xValue,1) == "'" .or. LEFT(xValue,1) = '"'
			xValue := SUBSTR(xValue,2, LEN(xValue)-2)
		Endif
		aDatas[n,2] := xValue
	Endif
*/	
	If n > 0
		aDatas[n,2] := xValue
	Endif
Return
	
Function GetControlData(cData, c)
Local i, xData := ""
	If !HB_IsArray(c)
		c := hb_aTokens(c, ,.T.)
	Endif
	i := ASCAN(c, {|a| LEFT(a,LEN(cData)) == cData})
	If i> 0
		AEVAL( HB_aTokens(c[i], ,.T.), {|a| xData += a},2)
	Endif
Return xData

Function ParseLine(c, xData)
Local xTemp, n

	xTemp := hb_aTokens(c, , .T.)
	If (n := ASCAN(xTemp, {|a| a == XData})) > 0
		xTemp := xTemp[n+1]
	Else
		xTemp = NIL
	Endif
Return xTemp

Function GetPicture(cPicture, cDefault)
Local cValue := "", LookInPath := "" //hb_FNameDir(oMain:Cargo:cFileName)
	If !EMPTY(cPicture)
		cValue := ALLTRIM(STRTRAN(cPicture, '"', ''))
		cValue := STRTRAN(cValue, "'", '')

		If File(LookInPath+cValue )
			cValue := LookInPath+cValue
		Else
			cValue := cDefault
		Endif
	Endif
Return cValue

Procedure FastData(o, what)
Local aResult, n := ASCAN(o:aDatas, {|a| a[1] == what} )	//, oProperties
	aResult := MyInput(o:aDatas[n,2],;
					{	{"TEXTBOX", what, o:aDatas[n,2], 50, 50} },,,.F., .T. )
	If aResult[1] <> NIL
		ChangeProperty(o, n, aResult[1])
		oControlP:Cargo := NIL		// Para forzar redespliegue de propiedades
		ControlProperties(o)
	Endif
Return

Function PreProcessControl( cData, aArray ) 
Local i, j, aDatas := aArray[1], aEvents := aArray[2], xTemp, cLine, lComent := .F.
	
	If cData[1] = "@"
		For i := 1 to 4
			hb_aDel(cData, 1, .T.)
		Next
	ElseIf cData[1] = "DEFINE" .AND. cData[2] = "STATUSBAR"
		hb_aDel(cData, 1, .T.)
		hb_aDel(cData, 1, .T.)
	ElseIf cData[1] = "DEFINE"
		hb_aDel(cData, 1, .T.)
		hb_aDel(cData, 1, .T.)
		hb_aDel(cData, 1, .T.)
	Endif
		
//db_Text(hb_Dumpvar(cData, .T.))
	cLine := {}
	i := ASCAN(cData, {|a| UPPER(a) =="AT"})
	If i <> 0
		If RIGHT(cData[i+1],1) = ","
			xTemp := "AT "+cData[i+1]+cData[i+2]
			hb_aDel(cData, i+2, .T.)
			hb_aDel(cData, i+1, .T.)
			hb_aDel(cData, i, .T.)
		Else
			xTemp := "AT "+cData[i+1]
			hb_aDel(cData, i+1, .T.)
			hb_aDel(cData, i, .T.)
		Endif
		AADD(cLine, xTemp)
	Endif

	For i := 1 TO LEN(cData)
		xTemp := UPPER(cData[i])
		If ( j := ASCAN(aDatas, {|a| a[1] == xTemp }) ) > 0 .OR. ( j := Data_Options(xTemp) ) > 0
lComent := .F.
			If HB_IsLogical( aDatas[j,2] )
				If j = dREADONLY .AND. i < LEN(cData)
					If TYPE(cData[i+1]) = 'A'
						AADD(cLine, aDatas[j,1]+" "+cData[i+1] )
						i++
					Else
						AADD(cLine, aDatas[j,1])
					Endif
				Else
					AADD(cLine, aDatas[j,1])
				Endif
			Else
				AADD(cLine, aDatas[j,1]+" "+cData[i+1] )
				i ++
			Endif
		ElseIf ( j := ASCAN(aEvents, {|a| a[1] == xTemp }) ) > 0 .OR. ( j := Event_Options(xTemp) ) > 0
lComent := .F.
			// Events only
				AADD(cLine, aEvents[j,1]+" "+cData[i+1] )
				i ++
		ELSE
//db_Text(xTemp)
			If !EMPTY(cLine)
				If HB_AT("//", xTemp) = 1
					lComent := .T.
				ElseIf !lComent
					// Don´t know what it is. Add To cLine
//					cLine[LEN(cLine)] +=" "+cData[i]	
					cLine[LEN(cLine)] += cData[i]			// Estoy quitando el espacio que agrego arriba
				Endif
//db_Text(ATAIL(cLine))
			Endif
		Endif
	Next
RETURN cLine

Function GetDataArray(cType)
	DO CASE
	CASE cType == "WINDOW"
		Return {WINDOW_DATAS, WINDOW_EVENTS}

	CASE cType == 'PAGE'
		Return {TABPAGE_DATAS, {{"",""}}}

	CASE cType == 'STATUSBAR'
		Return {STATUSBAR_DATAS,STATUSBAR_EVENTS}

	CASE cType == 'STATUSITEM'
		Return {STATUSITEM_DATAS,STATUSBAR_EVENTS}

	CASE cType == 'TBUTTON'
		Return {TBUTTON_DATAS, STATUSBAR_EVENTS}

	CASE cType == 'TOOLBAR'
		Return {TOOLBAR_DATAS, TBUTTON_EVENTS}
	ENDCASE
Return {SUPPORTED_DATAS, {{"",""}}}

Function ParseArray(cArray)
Local c, cNext := {","}, aResult := {}, cStr := ''

	// Make sure it is an array in text form
	// First character must be '{' and last should be '}'
	cArray := ALLTRIM(cArray)
	If LEFT(cArray,1) <> '{' .OR. RIGHT(cArray,1) <> '}'
		Return aResult
	Endif
	
	// Take out first and last ('{' and '}'
	cArray := SUBSTR(cArray,2, LEN(cArray)-2)

	For EACH c in cArray
		If c == '{'		// Array or block
			cStr += c
			AADD(cNext, '}' )	// look until we find the corresponding end
		ElseIf c == '('
			cStr += c
			AADD(cNext, ')' )
/*		ElseIf c == '"'
			cStr += c
			AADD(cNext, '"' )
		ElseIf c == "'"
			cStr += c
			AADD(cNext, "'" ) */
		ElseIf c == ATAIL(cNext)
			If ATAIL(cNext) == ','
				AADD(aResult, TRIM(cStr))
				cStr := ''
			Else
				cStr += c
				hb_aDel(cNext, Len(cNext), .T.)
			Endif
		Else
			cStr += c
		Endif
	Next
	AADD(aResult, cStr)
	AEVAL(aResult, {|a, n| aResult[n] := ALLTRIM(a)} )
Return aResult

// Esta funcion toma un string y lo convierte en array de strings.
// Similar a hb_aTokens(cString, " ") pero con la diferencia que lo hace de forma inteligente
// tomando en cuenta si es string, codeblock o arreglo en forma de string	
Function MakeArray(cString)
Local c, cNext := {" "}, aResult := {}, cStr := ''

	// Make sure it is a String 
	If !HB_IsChar(cString)
		Return aResult
	Endif
	
	For EACH c in cString
		If c == '{'				// Start of Array or block
			cStr += c
			AADD(cNext, '}' )	// look until we find the corresponding end
		ElseIf c $ '('			// Start of parentesis
			cStr += c
			AADD(cNext, ')' ) // Add to end of look for text
		ElseIf c == "'"
			cStr += c
			If ATAIL(cNext) == "'"						// start or end of text
				hb_aDel(cNext, Len(cNext), .T.)	 	// if at the end of look for text, then it is the end of text
				If ATAIL(cNext) $ "})"					// could be strings in a array or block, keep adding
				Else					
					AADD(aResult, TRIM(cStr))			// it is the end of text, add to array
					cStr := ''
				Endif
			Else
				AADD(cNext, "'" )						// begining of text, add to look for next
			Endif
		ElseIf c == '"'
			cStr += c
			If ATAIL(cNext) == '"'
				hb_aDel(cNext, Len(cNext), .T.)
				If ATAIL(cNext) $ "})"				//could be strings in a array or block
				Else
					AADD(aResult, TRIM(cStr))
					cStr := ''
				Endif
			Else
				AADD(cNext, '"' )
			Endif
		ElseIf c == ATAIL(cNext)
			If ATAIL(cNext) == ' '
				If !EMPTY(cStr)
					AADD(aResult, TRIM(cStr))
				Endif
				cStr := ''
			Else
				cStr += c
				hb_aDel(cNext, Len(cNext), .T.)
			Endif
		Else
			cStr += c
		Endif
	Next
	IF !EMPTY(cStr)
		AADD(aResult, cStr)
	Endif
	AEVAL(aResult, {|a, n| aResult[n] := ALLTRIM(a)} )
Return aResult

// Esta función regresa string sin las comillas sencillas o dobles	
Function Comillas(xData, lPut)
Local xRet := xData
DEFAULT lPut TO .F.
	If !EMPTY(xData) 
		If (Left(xData,1) == "'" .or. LEFT(xData,1) = '"')
			If !lPut
				xRet := SUBSTR(xData,2, LEN(xData)-2)
			Endif
		ElseIf lPut
			xRet := "'"+xData+"'"
		Endif
	Endif
	If xData = "NIL"
		xRet := ''
	Endif
Return xRet	