
namespace modifies Farm {
    
    abstract class Action {
        function constructor( object element ) {
        }
        function invoke() {
            return false;
        }
    }
    
    class PerformAction extends Farm.Action {
        static function constructor() {
            Farm.Yard.registerAction( 'perform', self );
        }
        
        string target;
        string action;
        function constructor( string t, string a ) {
            .target = t;
            .action = a;
        }
        function constructor( object element ) {
            array attributes = element.getAttributes();
            .target = attributes['target'];
            .action = attributes['action'];
        }
        function invoke() {
            if( Array.keyExists(Farm.targets,.target) ) {
                object o = Farm.targets[.target];
                number rval = false;
                
                Console.println( " -> Target '${o.uid}':\n" );
                rval = Farm.invokeTargetAction( .target, .action );
                Console.println( "" );
                return rval;
            }
            Farm.displayAction('error', "No such target '${.target}'");
            return false;
        }
    }
    
    class CopyFilesAction extends Farm.Action {
        static function constructor() {
            Farm.Yard.registerAction( 'copy', self );
        }
        
        array filelist;
        string target;
        number filter;
        
        function constructor( object element ) {
            array attributes = element.getAttributes();
            array filelist = [];
            
            if( Array.keyExists(attributes,'file') ) {
                filelist = [ Farm.expandStringProperties(attributes['file']) ];
            } else {
                Array.each( element.getChildren() ) using ( child ) {
                    array a = Farm.Yard.walkFileDescripton( child );
                    Array.each( a ) using ( file ) {
                        filelist[] = Farm.expandStringProperties(file);
                    };
                };
            }
            
            .filelist = filelist;
            .target = Farm.expandStringProperties(attributes['target']);
            if( Array.keyExists(attributes,'filter') )
                .filter = true;
        }
        function invoke() {
            number success = true;
            Array.each( .filelist ) using ( file ) {
                if( not .filter ) 
                    success = Farm.copyFile( file, "${.target}/${Farm.basename(file)}", 0644 );
                else
                    success = Farm.filterCopyFile( file, "${.target}/${Farm.basename(file)}", 0644 );
                return success;
            };
            return success;
        }
    }
    
    class ExecuteAction extends Farm.Action {
        
        static function constructor() {
            Farm.Yard.registerAction( 'execute', self );
        }
        
        array programs;
        string args;
        function constructor( object element ) {
            array attributes = element.getAttributes();
            .programs = String.toArray(attributes['program'],',');
            .args = attributes['arguments'];
        }
        function invoke() {
            number didRun = false;
            Array.each( .programs ) using ( program ) {
                string path = Farm.locateBinary(program, Farm.searchPaths());
                if( path == "" )
                    return;
                Farm.displayAction('execute', "Running $program");
                didRun = Farm.invokeExternalProgram("$path ${.args}");
                return false; // We jump out quickly
            };

            if( not didRun )
                Farm.displayAction('error', "Unable to locate either of the programs '${Array.join(.programs,',')}'");    
            return didRun;
        }            
    }
    
    class Phase {
        array actions;
        string dependancy;
        string id;
        
        function constructor( string id ) {
            .id = id;
        }
        function addAction( object p ) {
            if( p != null )
                .actions[] = p;
        }
        function invoke() {
            number success;
            
            Farm.processed_phases[] = .id;
            
            if( .dependancy != "" and Array.keyExists(Farm.phases, .dependancy) ) {
                object o = Farm.phases[.dependancy];
                
                if( not o.invoke() )
                {
                    Farm.displayAction('error',"Unable to invoke dependancy '${.dependancy}' of phase '${.id}'");
                    return false;
                }                    
            }
            
            Console.println( "Processing Action '${.id}'\n" );
            Array.each( .actions ) using ( action ) {
                success = action.invoke();
                return success;
            };
            
            return success;
        }
    } 
    
    class CleanPhase extends Farm.Phase {
        function invoke() {
            Farm.displayAction('clean',"Removing Directory: FarmYard");
            return Farm.destroyPath(Farm.yardDir());
        }
    }
}
