﻿;-- TIME_STAMP   2017-01-30 21:14:49   v 0.1

#cs ================================================================================================
FUNCTIONS

_FolderStruct_WriteToFile
	Gets the structure of folders from a given root path and write this to an file

_FolderStruct_CreateFromFile
	Creates folder in the same structure like the given structure file in a given target path

_FolderStruct_PathDepth
	Sets a new value for the maximum possible path depth or gets the current one.

====================================================================================================
Read a folder structure, root path is "d:\archive"
e.g.:
d:\archive\user
d:\archive\user\john
d:\archive\user\john\letter
d:\archive\user\john\letter\privat
d:\archive\user\john\letter\work
d:\archive\user\john\video
d:\archive\user\john\video\cats
d:\archive\user\john\video\dogs
d:\archive\user\marie
d:\archive\user\marie\photo
d:\archive\user\marie\photo\flowers
d:\archive\user\marie\photo\horses

gets this structure file:
1|user
1.1|john
1.1.1|letter
1.1.1.1|privat
1.1.1.2|work
1.1.2|video
1.1.2.3|cats
1.1.2.4|dogs
1.2|marie
1.2.3|photo
1.2.3.5|flowers
1.2.3.6|horses

#ce ================================================================================================

#include-once
#include <File.au3>

; #FUNCTION# =======================================================================================
; Name ..........: _FolderStruct_WriteToFile
; Description ...: Gets the structure of folders from a given root path and write this to an file
; Syntax ........: _FolderStruct_WriteToFile($_sPathRoot, $_sFileStruct[, $_sDelim = -1])
; Parameter(s)...: $_sPathRoot    Path of the folder, which structure will be stored
; ...............: $_sFileStruct  Path of the file, which will store this structure
; .....optional..: $_sDelim       Delimiter between order string and folder name.
; ...............:                Default is -1 -> Opt("GUIDataSeparatorChar")
; Return values .: Success  1
; ...............: Failure  0  @error 1 - Path not found or invalid
; ...............:                    2 - No files/folders found
; ...............:                    3 - Failed to open the struct file for writing
; ...............:                    4 - Failed to write
; Author ........: BugFix ( AutoIt@bug-fix.info )
; ==================================================================================================
Func _FolderStruct_WriteToFile($_sPathRoot, $_sFileStruct, $_sDelim=-1)
	$_sPathRoot = StringRegExpReplace($_sPathRoot, '\\*$', '')
	If $_sDelim = -1 Then $_sDelim = Opt("GUIDataSeparatorChar")
	; $FLTAR_FOLDERS=2, $FLTAR_RECUR=1, $FLTAR_SORT=1, $FLTAR_FULLPATH=2
	Local $aFolder = _FileListToArrayRec($_sPathRoot, "*", 2, 1, 1, 2)
	If @error Then Return SetError((@error=9?2:1),0,0)
	Local $aLevel[_FolderStruct_PathDepth(-1)] = [1]
	Local $sWrite = '', $aTmp
	For $i = 1 To $aFolder[0]
		$aTmp = __GetFolderLevel($_sPathRoot, $aFolder[$i])
		$sWrite &= __OrderNumber($aLevel, $aTmp[0]) & $_sDelim & $aTmp[1] & @CRLF
	Next
	Local $fH = FileOpen($_sFileStruct, 2+8+128) ; 2=$FO_OVERWRITE  8=$FO_CREATEPATH  128=$FO_UTF8
	If $fH = -1 Then Return SetError(3,0,0)
	Local $iErr = 0, $iSucc = FileWrite($fH, $sWrite)
	FileClose($fH)
	If $iSucc <> 1 Then $iErr = 4
	Return SetError($iErr,0,$iSucc)
EndFunc  ;==>_FolderStruct_WriteToFile


; #FUNCTION# =======================================================================================
; Name ..........: _FolderStruct_CreateFromFile
; Description ...: Creates folder in the same structure like the given structure file in a given target path
; Syntax ........: _FolderStruct_CreateFromFile($_sPathTarget, $_sFileStruct[, $_sDelim = -1[, $_iOutput = 0]])
; Parameter(s)...: $_sRootTarget  Path to the folder where the structure is to be created
; ...............: $_sFileStruct  Path to the file containing the structure
; .....optional..: $_sDelim       Delimiter between order string and folder name in structure file.
; ...............:                Default is -1 -> Opt("GUIDataSeparatorChar")
; .....optional..: $_iOutput      0 (Default) none output, 1 output to console (result of each create command)
; Return Value(s): Succes   1
; ...............: Failure  0  @error  1 - failed to read structure file
; ...............:                     2 - structure file is empty
; Author ........: BugFix ( AutoIt@bug-fix.info )
; ==================================================================================================
Func _FolderStruct_CreateFromFile($_sPathTarget, $_sFileStruct, $_sDelim=-1, $_iOutput=0)
	$_sPathTarget = StringRegExpReplace($_sPathTarget, '\\*$', '')
	If $_sDelim = -1 Then $_sDelim = Opt("GUIDataSeparatorChar")
	Local $fH = FileOpen($_sFileStruct, 128) ; 128=$FO_UTF8
	If $fH = -1 Then Return SetError(1,0,0)
	Local $sRead = FileRead($fH)
	If @error Then Return SetError(1,0,0)
	FileClose($fH)
	Local $aFolder = StringRegExp($sRead, "([\d\.]*)\" & $_sDelim & "([^\r\n]+)", 3)
	If Not IsArray($aFolder) Then Return SetError(2,0,0)
	Local $n = 1, $aPathes[(UBound($aFolder)/2)+1][2] = [[UBound($aFolder)/2]]  ; == [[Path, sOrder]]
	Local $sOrderParent, $sFullPath
	For $i = 0 To UBound($aFolder) -2 Step 2
		$sOrderParent = __GetParentOrderNumber($aFolder[$i])
		Switch $sOrderParent
			Case ''
				$aPathes[$n][0] = $aFolder[$i+1] & '\'
			Case Else
				For $j = 1 To $n -1
					If $aPathes[$j][1] = $sOrderParent Then
						$aPathes[$n][0] = $aPathes[$j][0] & $aFolder[$i+1] & '\'
						ExitLoop
					EndIf
				Next
		EndSwitch
		$aPathes[$n][1] = $aFolder[$i] ; sOrder
		; DirCreate
		$sFullPath = $_sPathTarget & '\' & StringTrimRight($aPathes[$n][0], 1)
		If Not FileExists($sFullPath) Then
			If DirCreate($sFullPath) = 0 Then
				__Output(StringFormat('!! ERROR - Failed to create the folder "%s"', $sFullPath), $_iOutput)
			Else
				__Output(StringFormat('>> CREATED "%s"', $sFullPath), $_iOutput)
			EndIf
		EndIf
		$n += 1
	Next
	Return 1
EndFunc  ;==>_FolderStruct_CreateFromFile


; #FUNCTION# =======================================================================================
; Name ..........: _FolderStruct_PathDepth
; Description ...: Sets a new value for the maximum possible path depth or gets the current one.
; Syntax ........: _FolderStruct_PathDepth([$_iDepth = 256])
; Parameters ....: $_iLevel     [optional] The new value to set. Default = 256, the minimum is 64.
; ...............:              maximum is VAR_SUBSCRIPT_ELEMENTS (16,777,216)
; ...............:              '-1' gets the current value.
; Return values .: The new/current path depth
; Author ........: BugFix ( AutoIt@bug-fix.info )
;===================================================================================================
Func _FolderStruct_PathDepth($_iDepth=256)
	Local Static $MAX_PATHDEPTH = 256
	Local Const $VAR_SUBSCRIPT_ELEMENTS = 16777216
	If $_iDepth > 0 Then $MAX_PATHDEPTH = $_iDepth <> $MAX_PATHDEPTH ? _
		($_iDepth < 64 ? 64 : ($_iDepth > $VAR_SUBSCRIPT_ELEMENTS ? $VAR_SUBSCRIPT_ELEMENTS : $_iDepth)) : $MAX_PATHDEPTH
	Return $MAX_PATHDEPTH
EndFunc  ;==>_FolderStruct_PathDepth



;===================================================================================================
Func __GetFolderLevel($_sRoot, $_sPath)
	Local $sFolder = StringTrimLeft($_sPath, StringInStr($_sPath, '\', 0, -1))
	Local $sBody = StringTrimLeft($_sPath, StringLen($_sRoot))
	StringReplace($sBody, '\', '\')
	Local $aRet[2] = [@extended, $sFolder]
	Return $aRet
EndFunc  ;==>__GetFolderLevel

Func __OrderNumber(ByRef $_aLevel, $_iLevel)
	$_aLevel[$_iLevel] += 1
	Local $sOrder = ''
	For $i = 1 To $_iLevel
		$sOrder &= $_aLevel[$i] & '.'
	Next
	Return StringTrimRight($sOrder, 1)
EndFunc  ;==>__OrderNumber

Func __GetParentOrderNumber($_sOrder)
	If $_sOrder = '1' Then Return ''
	Local $iPos = StringInStr($_sOrder, '.', 1, -1)
	Return StringLeft($_sOrder, $iPos -1)
EndFunc  ;==>__GetParentOrderNumber

Func __Output($_sOutput, $_iConsole)
	If $_iConsole = 0 Then Return
	ConsoleWrite($_sOutput & @CRLF)
EndFunc  ;==>__Output
;===================================================================================================