// ==========================================================================
// Author:  Yee Hsu
// Date:    8/5/2008
// File:    WebMiner.cpp
//
// Desc:    WebMiner base architecture written using advanced C# topics
//          and coding practices.
// ==========================================================================

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Threading;
using System.Reflection;
using CommonLib;

namespace WebMiner
{
    public class MinerManager
    {
        private Queue<XmlConfStruct> qFunctionId = null;

        // populates the queue and executes X number of threads on that queue

        public void ProcessQueue()
        {
            Common.DataMineLog("-----------------------------------------------------------------");
            Common.DataMineLog("WebMiner Started.");

            this.qFunctionId = new Queue<XmlConfStruct>(Configuration.qFunctionId.ToArray());            

            Thread[] t = new Thread[Configuration.nNumThreads];

            for (int i = 0; i < t.Length; i++)
            {
                t[i] = new Thread(this.ExecuteUpdates);
                t[i].Name = "DataMineThread_" + i.ToString();
                t[i].Start();
            }

            for (int i = 0; i < t.Length; i++)
            {
                t[i].Join(1000 * 60 * 30);          // half hour wait for each queue thread
            }
            Common.DataMineLog("All Done. Waiting for next update...");
        }

        // each thread executes this function, but only one exclusive thread
        // may enter the CS, create another thread within the CS and operate on it

        private void ExecuteUpdates()
        {
            while (this.qFunctionId.Count > 0)
            {
                Thread.Sleep(100);
                XmlConfStruct xmlc = new XmlConfStruct();
                Thread tt = null;

                //////////////////////////////////     CRITICAL SECTION       ///////////////////////////////////////
                lock (this)
                {
                    if (this.qFunctionId.Count > 0)
                    {
                        xmlc = this.qFunctionId.Dequeue();
                        tt = new Thread(this.ExecuteFunctionId);
                        tt.Name = Thread.CurrentThread.Name + "_" + xmlc.nFunctionId;
                        tt.Start(xmlc);
                    }
                }
                /////////////////////////////////////////////////////////////////////////////////////////////////////

                if (tt != null)
                    tt.Join(1000 * 60 * 5);          // five minute wait for each update id
            }
        }

        // use reflections to actually call the underlying function

        private void ExecuteFunctionId(object obj)
        {
            object[] objs = new object[1] { obj };
            XmlConfStruct xmlconf = (XmlConfStruct)objs[0];
            xmlconf.sMethodName = "UpdateMethod_" + xmlconf.nFunctionId.ToString();
            xmlconf.sThreadName = Thread.CurrentThread.Name;

            try
            {
                // Dynamic Runtime Execution with Reflections here
                Type t = Assembly.GetExecutingAssembly().GetType("WebMiner.Vendors.Vendor");
                t.InvokeMember(xmlconf.sMethodName, BindingFlags.InvokeMethod, null, Activator.CreateInstance(t), objs);
            }
            catch (Exception e)
            {
                Common.DataMineLog("Error In Method: " + xmlconf.sMethodName);
            }
        }
    }
}