// List of DLL results, empty if no DLLs were found
        // else list of results. bool = true no error, false error.  String contains error string, or result string
        public List <Tuple <bool, string, string> > ActionCommand(string dllname, string cmd, string[] paras)
        {
            List <Tuple <bool, string, string> > resultlist = new List <Tuple <bool, string, string> >();

            if (dllname.Equals("All", StringComparison.InvariantCultureIgnoreCase))
            {
                foreach (EDDDLLCaller caller in dlls)
                {
                    resultlist.Add(AC(caller, cmd, paras));
                }
            }
            else
            {
                EDDDLLCaller caller = FindCaller(dllname);
                if (caller != null)
                {
                    resultlist.Add(AC(caller, cmd, paras));
                }
                else
                {
                    resultlist.Add(new Tuple <bool, string, string>(false, dllname, "Cannot find DLL "));
                }
            }

            return(resultlist);
        }
        // return loaded, failed, notallowed
        public Tuple <string, string, string> Load(string directory, string ourversion, string dllfolder, EDDDLLIF.EDDCallBacks callbacks, string allowed)
        {
            string loaded     = "";
            string failed     = "";
            string notallowed = "";

            if (!Directory.Exists(directory))
            {
                failed = "DLL Folder does not exist";
            }
            else
            {
                FileInfo[] allFiles = Directory.EnumerateFiles(directory, "*.dll", SearchOption.TopDirectoryOnly).Select(f => new FileInfo(f)).OrderBy(p => p.LastWriteTime).ToArray();

                string[] allowedfiles = allowed.Split(',');

                foreach (FileInfo f in allFiles)
                {
                    string filename = System.IO.Path.GetFileNameWithoutExtension(f.FullName);

                    EDDDLLCaller caller = new EDDDLLCaller();

                    if (caller.Load(f.FullName))                                                                                                                              // if loaded (meaning it loaded, and its got EDDInitialise)
                    {
                        if (allowed.Equals("All", StringComparison.InvariantCultureIgnoreCase) || allowedfiles.Contains(filename, StringComparer.InvariantCultureIgnoreCase)) // if allowed..
                        {
                            if (caller.Init(ourversion, dllfolder, callbacks))                                                                                                // must init
                            {
                                dlls.Add(caller);
                                loaded = loaded.AppendPrePad(caller.Name, ",");
                            }
                            else
                            {
                                string errstr = caller.Version.HasChars() ? (": " + caller.Version.Substring(1)) : "";
                                failed = failed.AppendPrePad(caller.Name + errstr, ",");
                            }
                        }
                        else
                        {
                            notallowed = notallowed.AppendPrePad(caller.Name, ",");
                        }
                    }
                }
            }

            return(new Tuple <string, string, string>(loaded, failed, notallowed));
        }
        public Tuple <bool, string, string> AC(EDDDLLCaller caller, string cmd, string[] paras)
        {
            string r = caller.ActionCommand(cmd, paras);

            if (r == null)
            {
                return(new Tuple <bool, string, string>(false, caller.Name, "DLL does not implement ActionCommand"));
            }
            else if (r.Length > 0 && r[0] == '+')
            {
                return(new Tuple <bool, string, string>(true, caller.Name, r.Mid(1)));
            }
            else
            {
                return(new Tuple <bool, string, string>(false, caller.Name, r.Mid(1)));
            }
        }
        // item1 = true if found, item2 = true if caller implements.
        public Tuple <bool, bool> ActionJournalEntry(string dllname, EDDDLLIF.JournalEntry nje)
        {
            if (dllname.Equals("All", StringComparison.InvariantCultureIgnoreCase))
            {
                foreach (EDDDLLCaller caller in dlls)
                {
                    caller.ActionJournalEntry(nje);
                }

                return(new Tuple <bool, bool>(true, true));
            }
            else
            {
                EDDDLLCaller caller = FindCaller(dllname);
                return(caller != null ? new Tuple <bool, bool>(true, caller.ActionJournalEntry(nje)) : new Tuple <bool, bool>(false, false));
            }
        }
        public string Load(string directory, string ourversion, string dllfolder, EDDDLLIF.EDDCallBacks callbacks, string allowed)
        {
            string res = "";

            if (!Directory.Exists(directory))
            {
                return("No Folder");
            }

            FileInfo[] allFiles = Directory.EnumerateFiles(directory, "*.dll", SearchOption.TopDirectoryOnly).Select(f => new FileInfo(f)).OrderBy(p => p.LastWriteTime).ToArray();

            foreach (FileInfo f in allFiles)
            {
                string name = "<" + System.IO.Path.GetFileNameWithoutExtension(f.FullName) + ">";

                EDDDLLCaller caller = new EDDDLLCaller();

                if (caller.Load(f.FullName))                                                                                                                           // if loaded (meaning it loaded, and its got EDDInitialise)
                {
                    if (allowed.Equals("All", StringComparison.InvariantCultureIgnoreCase) || allowed.IndexOf(name, StringComparison.InvariantCultureIgnoreCase) >= 0) // if allowed..
                    {
                        if (caller.Init(ourversion, dllfolder, callbacks))                                                                                             // must init
                        {
                            dlls.Add(caller);
                        }
                        else
                        {
                            return("DLL " + name + " Failed");
                        }
                    }
                    else
                    {
                        res += name;
                    }
                }
            }

            return(res);
        }
        // NULL/False if no DLL found, or <string,true> if DLL found, string may be null if DLL does not implement action command
        public Tuple <string, bool> ActionCommand(string dllname, string cmd, string[] paras)
        {
            if (dllname.Equals("All", StringComparison.InvariantCultureIgnoreCase))
            {
                string ret = "";

                foreach (EDDDLLCaller caller in dlls)
                {
                    string r = caller.ActionCommand(cmd, paras);
                    if (r != null)
                    {
                        ret += r + ";";
                    }
                }

                return(new Tuple <string, bool>(ret, true));
            }
            else
            {
                EDDDLLCaller caller = FindCaller(dllname);
                return(caller != null ? new Tuple <string, bool>(caller.ActionCommand(cmd, paras), true) : new Tuple <string, bool>(null, false));
            }
        }