////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
//  File:   EventController.cs
//
//

using System;
using System.Threading;
using System.Runtime.CompilerServices;

using Microsoft.Singularity;
using Microsoft.Singularity.V1.Services;    
using Microsoft.Singularity.Eventing;
using System.Collections;

namespace Microsoft.Singularity.Eventing
{

    //
    //  Define here the controller class. A controller object
    //  defines the scope of the tracing / eventing, 
    //  defines the lifetime of the eventing related metadata such as
    //  event types, sources and consumers, and implicitely
    //  respects the isolation boundary for events. Queries and 
    //  traces accross controllers should use contracts. Queries / logging
    //  from SIPs to kernel use syscalls ABIs
    //

    [CLSCompliant(false)]
    [AccessedByRuntime("output to header : defined in EventController.cpp")]
    public abstract class Controller {

        //  Commonly all events / traces are using by default the local controller
        //  A SIP and kernel has the optional to instantiate additional controllers.

        internal static LocalController LocalControllerObject;

        //  Some events may choose for a system-wide visibility, in which case
        //  a SIP may refer through a system controller. For kernel, both system and
        //  local controller are the same.
        
        internal static Controller SystemControllerObject;

        //  default size for entry enumerations
        
        const ushort DefaultEntrySize = 256;

        //
        //  Define the accessor methods to the system and local controller
        //

        static public LocalController GetLocalController()
        {
            return LocalControllerObject;
        }

        static public Controller GetSystemController()
        {
            return SystemControllerObject;
        }

        static public bool IsSystemScope()
        {
#if SINGULARITY_KERNEL

            return true;

#else // SINGULARITY_KERNEL

            return false;

#endif // SINGULARITY_KERNEL
            
        }

        //  Public methods

        static public void InitializeSystem() {

            // Create the system controller if needed. The SIPs will
            // get a proxy controller object that will handle operations
            // as syscalls. 
            // TODO: Further optimizations may allow writing a more
            // efficient proxy that may use shared memory.

#if SINGULARITY_KERNEL

            KernelController controller = new KernelController();

            if (controller != null) {

                LocalControllerObject = controller;
                SystemControllerObject = LocalControllerObject;
                controller.Initialize();
            }
#else
            LocalController controller = new LocalController();

            if (controller != null) {

                LocalControllerObject = controller;

                //  For SIPs we need a proxy object that will handle the calls
                //  to the system controller

                SystemControllerObject = new SystemControllerProxy();
                
                controller.Initialize();
            }

#endif
            if (SystemControllerObject != null) {

                SystemControllerObject.Initialize();
                SystemControllerObject.RegisterController();
                QuerySession.InitializeQuerySystem();
            }

        }

        //  Avoid any cleanup that would normally happen when a storage is deleted or
        //  a source is de-registered during SIP shutdown. Beside the work is unnecessary,
        //  there are problems with the order of executing the finalizers at shutdown 
        
        internal static bool Finalized = false;
        
        static public void Finalize() {
            Finalized = true;
        }

        //  Private fields
        
        internal Mutex Lock;

        //
        //  Abstract methods
        //

        public abstract bool RegisterEvent(string eventName, 
                                           string eventDescription, 
                                           ref UIntPtr eventHandle);
        
        public abstract bool RegisterEventField(UIntPtr eventHandle, 
                                                string fieldName, 
                                                UInt16 offset, 
                                                UInt16 type);

        public abstract bool RegisterEventGenericField(UIntPtr eventHandle, 
                                                       string fieldName, 
                                                       UInt16 offset, 
                                                       UInt16 size,
                                                       UIntPtr fieldTypeHandle);

        public abstract bool RegisterEnum(string enumName, 
                                          UInt16 type, 
                                          ref UIntPtr eventHandle);
        
        public abstract bool RegisterEnumValue(UIntPtr eventHandle, 
                                               string valueName, 
                                               UInt64 value, 
                                               byte flagChar);
        
        public abstract UIntPtr WalkEventDescriptor(UIntPtr eventHandle,
                                                    UIntPtr currentField,
                                                    ref UInt16 offset,
                                                    ref UInt16 type,
                                                    ref string bufferName);

        public abstract bool GetSourceInformation(UIntPtr sourceHandle,
                                                    ref UIntPtr storageHandle,
                                                    ref UIntPtr eventType,
                                                    ref UInt16 count,
                                                    ref string bufferName);

        //  Virtual methods
        
        internal virtual void Initialize()
        {
            Lock = new Mutex();
        }

        //
        //  Controller related methods
        //
        
        public virtual bool RegisterController()
        {
            return true;
        }

        public virtual void UnRegisterController(int processId)
        {
        }

        //
        //  Storage related methods
        //

        public virtual EventingStorage OpenStorage(UIntPtr storageHandle) 
        {
            return null;
        }

        //
        //  Source related methods
        //

        public virtual bool RegisterSource(EventSource source)
        {
            return false;
        }
        
        public virtual void UnRegisterSource(EventSource source){}


        //
        //  Query functionality methods
        //
        
        public virtual int QuerySourcesList(UIntPtr [] buffer, int size)
        {
            return 0;
        }

        public virtual int QueryEventTypeList(UIntPtr [] buffer, int size)
        {
            return 0;
        }

        public virtual bool QueryActiveEntry(UIntPtr sourceHandle,
                                             int index,
                                             ref QueryBuffer entryBuffer)
        {
            return false;
        }

        public virtual void EnumerateActiveSources(QuerySourceDelegate sourceDelegate,
                                                   ActiveSourceEntryDelegate activeEntryDelegate,
                                                   QueryEntryDelegate entryDelegate,
                                                   ushort maxEntrySize,
                                                   ref EnumerationContext context)
        {

            if (maxEntrySize == 0) {
                maxEntrySize = DefaultEntrySize;
            }

            //  Create a temporary buffer to store the temporary query information
            
            QueryBuffer entryBuffer = new QueryBuffer(maxEntrySize);

            if ((entryBuffer == null) || (sourceDelegate == null)) {
                return;
            }

            //  Prepare to query the controller for the source list. We just pick up an number
            //  that would represent the limit for most common cases as the initial guess.

            int currentSize = 100;
            UIntPtr [] sourceArray = new UIntPtr[currentSize];

            if (sourceArray != null) {

                //  Query the controller for the actual source list

                int sourceCount = QuerySourcesList(sourceArray, currentSize);

                //
                //  The array was not large enough, attempt again with the new size

                while (sourceCount > currentSize) {

                    sourceArray = new UIntPtr[sourceCount];
                    sourceCount = QuerySourcesList(sourceArray, currentSize);
                }

                //
                //  We sucessfully received an array of entries. We walk them and build the
                //  required information
                //
                
                for (int i = 0; i < sourceCount; i++) {
                    
                    UIntPtr sourceHandle = sourceArray[i];
                    UIntPtr storageHandle = 0;
                    UIntPtr eventType = 0;
                    UInt16 count = 0;
                    string bufferName = "";

                    if (GetSourceInformation(sourceHandle, 
                                             ref storageHandle, 
                                             ref eventType, 
                                             ref count, 
                                             ref bufferName)) {

                        if (storageHandle == 0) {

                            //
                            //  This is an active source. The eventing has no information
                            //  about the storage, it has instead information about the
                            //  types of events handled by this source
                            //

                            EventDescriptor descriptor = QuerySession.GetEventDescriptor(this, 
                                                                                         eventType);

                            if (descriptor != null) {

                                //  The source is valid, call the delegate with the appropriate
                                //  arguments filled in
                                // TODO: Also retrieve the control flags status
                                

                                if (!sourceDelegate(sourceHandle, 
                                                    storageHandle, 
                                                    eventType, 
                                                    count, 
                                                    bufferName, 
                                                    descriptor, 
                                                    ref context)) {
                                    break;
                                }
                                
                                if (entryDelegate != null) {

                                    //  The caller also provided an entry delegate. We need in that
                                    //  case to also enumerate all entries from the active source

                                    for (int index = 0; index < count; index++) {

                                        if (!QueryActiveEntry(sourceHandle, 
                                                              index, 
                                                              ref entryBuffer)) {
                                            break;
                                        }

                                        activeEntryDelegate(sourceHandle, 
                                                            index, 
                                                            descriptor, 
                                                            entryBuffer, 
                                                            ref context);
                                    }
                                }
                            }
                        } else {

                            //  This source has an associated storage. Enumerate the entries from
                            //  the storage
                            // TODO: we might also want to filter the sources inside the storage
                            // since multiple sources can share the same storage

                            if (!sourceDelegate(sourceHandle, 
                                                storageHandle, 
                                                eventType, 
                                                count, 
                                                bufferName, 
                                                null, 
                                                ref context)) {
                                break;
                            }
                            
                            EventingStorage storage = OpenStorage(storageHandle);

                            if (storage != null) {

                                // Instantiate a query session for the storage and
                                // enumerate the entries passing the provided delegate

                                QuerySession query = new QuerySession();
                                
                                if ((query != null) && (context != null) && 
                                     query.Initialize(storage, false)) {

                                    query.EnumerateEntries(entryDelegate, ref context);
                                }
                            }
                        }

                    }
                }
            }
        }

        public static unsafe bool GetSharedSourceHandles(uint infoId,
                                                         out UIntPtr storageHandle, 
                                                         out UIntPtr sourceHandle, 
                                                         out UIntPtr eventTypeHandle )
        {

            if ((infoId == TracingInfo) || (infoId == MonitoringInfo)) {

                UIntPtr tmpStorageHandle;
                UIntPtr tmpSourceHandle;
                UIntPtr tmpEventTypeHandle;

                if (GetSharedSourceHandlesInternal(infoId, 
                                                   &tmpStorageHandle, 
                                                   &tmpSourceHandle, 
                                                   &tmpEventTypeHandle)) {

                    storageHandle = tmpStorageHandle;
                    sourceHandle = tmpSourceHandle;
                    eventTypeHandle = tmpEventTypeHandle;

                    return true;
                }
            }

            storageHandle = 0;
            sourceHandle = 0;
            eventTypeHandle = 0;

            return false;
        }

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        public const uint TracingInfo = 1;

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        public const uint MonitoringInfo = 2;
        
        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe bool GetSharedSourceHandlesInternal(uint infoId,
                                                                        UIntPtr * storageHandle, 
                                                                        UIntPtr * sourceHandle, 
                                                                        UIntPtr * eventTypeHandle );
    }

    
    [CLSCompliant(false)]
    [AccessedByRuntime("output to header : defined in EventController.cpp")]
    public class LocalController : Controller {

        //
        // Internal fields
        //

        //  The type repository is a permanent
        
        internal EventingStorage TypesRepository;
        internal Hashtable EventTable;
        internal Hashtable SourcesHandleTable;
        internal Hashtable SourcesLookupTable;

        internal ControllerLogger InternalSource;

        internal const uint BUFFER_EXPANSION_SIZE = 0x10000;

        //  Public methods

        //  Private methods
        
        internal override void Initialize() {

            base.Initialize();
            
            EventTable = new Hashtable();
            SourcesLookupTable = new Hashtable();
            SourcesHandleTable = new Hashtable();

            UIntPtr RepositoryStorageHandle = FetchLocalStorage();

            if (RepositoryStorageHandle != 0) {
                
                TypesRepository = EventingStorage.CreateStorageFromHandle(RepositoryStorageHandle);

                //  Fetch now the existing source list created before initializing the controller

                int currentSize = 20;
                UIntPtr [] sourceArray = new UIntPtr[currentSize];

                if (sourceArray != null) {

                    unsafe {
                        fixed(UIntPtr * ptr = sourceArray) {

                            int sourceCount = QuerySystemSources(ptr, (ushort)currentSize);

                            while (sourceCount > currentSize) {

                                sourceArray = new UIntPtr[sourceCount];
                                sourceCount = QuerySystemSources(ptr, (ushort)currentSize);
                            }

                            for (int i = 0; i < sourceCount; i++) {

                                UIntPtr sourceHandle = sourceArray[i];
                                UIntPtr storageHandle = 0;
                                string bufferName = "";

                                if (GetNativeSourceName(sourceHandle, ref storageHandle, ref bufferName)) {

                                    EventSource source = new EventSource(this, bufferName, storageHandle);
                                    
                                    if (source != null) {
                                        source.Register();
                                    }
                                }
                            }
                        }
                    }

                }
                
            } else {

                TypesRepository = EventingStorage.CreateLocalStorage(QualityOfService.PermanentEvents,
                                                                     BUFFER_EXPANSION_SIZE);
                SetRepositoryStorage(TypesRepository.GetHandle());
            }
                
            string sourceName = "ControllerLog";
            
#if SINGULARITY_KERNEL

            sourceName = sourceName + "{kernel}";

#else
            unsafe {

                int argMaxLen = ProcessService.GetStartupArg(0, null, 0);
                char[] argArray = new char [argMaxLen];

            
                fixed (char *argptr = &argArray[0]) {
                    int len = ProcessService.GetStartupArg(0,
                                                           argptr,
                                                           argArray.Length);
                    sourceName = sourceName + "{"+String.StringCTOR(argptr, 0, len)+"}";
                    sourceName = sourceName + "(PID:"+ ProcessService.GetCurrentProcessId() +")";
                }
            }
#endif

            InternalSource = ControllerLogger.Create(sourceName, TypesRepository);
        }

        //  Event schema registration routines
        
        public override bool RegisterEvent(string eventName, 
                                           string eventDescription, 
                                           ref UIntPtr eventHandle) {

            Lock.AcquireMutex();
            object o = EventTable[eventName];
            
            if (o != null) {

                // Type already registered. Return the existing value
                eventHandle = (UIntPtr)o;
                Lock.ReleaseMutex();
                return false;
            }

            eventHandle = RegisterEventDescriptorInternal(eventName, eventDescription);

            while (eventHandle == 0) {

                if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {

                    Lock.ReleaseMutex();
                    return false;
                }

                eventHandle = RegisterEventDescriptorInternal(eventName, eventDescription);
            }

            EventTable[eventName] = eventHandle;
            
            Lock.ReleaseMutex();

            return true;
        }
            
        public override bool RegisterEventField(UIntPtr eventHandle, 
                                                string fieldName, 
                                                UInt16 offset, 
                                                UInt16 type) {

            UIntPtr field = RegisterEventFieldInternal(eventHandle, 
                fieldName, 
                offset, 
                type);

            while (field == 0) {

                Lock.AcquireMutex();
                if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {

                    Lock.ReleaseMutex();
                    return false;
                }

                Lock.ReleaseMutex();
                
                field = RegisterEventFieldInternal(eventHandle, 
                    fieldName, 
                    offset, 
                    type);
            }

            return true;
        }

        public override bool RegisterEventGenericField(UIntPtr eventHandle, 
                                                       string fieldName, 
                                                       UInt16 offset, 
                                                       UInt16 size,
                                                       UIntPtr fieldTypeHandle) {

            UIntPtr field = RegisterEventGenericFieldInternal(eventHandle, 
                                                              fieldName, 
                                                              offset,
                                                              size,
                                                              fieldTypeHandle);

            while (field == 0) {

                Lock.AcquireMutex();
                if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {

                    Lock.ReleaseMutex();
                    return false;
                }

                Lock.ReleaseMutex();
                
                field = RegisterEventGenericFieldInternal(eventHandle, 
                                                          fieldName, 
                                                          offset,
                                                          size,
                                                          fieldTypeHandle);
            }

            return true;
        }

        //
        //  Enumeration registration support
        //
        
        public override bool RegisterEnum(string enumName, 
                                          UInt16 type, 
                                          ref UIntPtr eventHandle) {

            Lock.AcquireMutex();
            object o = EventTable[enumName];
            
            if (o != null) {

                // Type already registered. Return the existing value
                eventHandle = (UIntPtr)o;
                Lock.ReleaseMutex();
                return false;
            }

            eventHandle = RegisterEnumDescriptorInternal(enumName, type);

            while (eventHandle == 0) {

                if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {

                    Lock.ReleaseMutex();
                    return false;
                }

                eventHandle = RegisterEnumDescriptorInternal(enumName, type);
            }

            EventTable[enumName] = eventHandle;
            
            Lock.ReleaseMutex();

            return true;
        }
            
        public override bool RegisterEnumValue(UIntPtr eventHandle, 
                                               string valueName, 
                                               UInt64 value, 
                                               byte flagChar) {

            UIntPtr field = RegisterValueDescriptorInternal(eventHandle, 
                                                            valueName, 
                                                            value, 
                                                            flagChar);

            while (field == 0) {

                Lock.AcquireMutex();
                if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {

                    Lock.ReleaseMutex();
                    return false;
                }

                Lock.ReleaseMutex();
                field = RegisterValueDescriptorInternal(eventHandle, 
                                                        valueName, 
                                                        value, 
                                                        flagChar);
            }

            return true;
        }

        //  Storage registration routines
        
        public bool RegisterStorage(EventingStorage Storage)
        {
            Lock.AcquireMutex();
            bool success = RegisterStorageImpl(Storage.GetHandle());
            Lock.ReleaseMutex();
            return success;
         }
    
        public void UnRegisterStorage(EventingStorage Storage)
        {
            if (!Controller.Finalized) {
                
                Lock.AcquireMutex();
                UnRegisterStorageImpl(Storage.GetHandle());
                Lock.ReleaseMutex();
            }
        }

        // Eventing source support routines

        public override bool RegisterSource(EventSource source)
        {
            // Sanity check against double registration
            if (source.SourceHandle != 0) {
                return false;
            }
            
            UIntPtr sourceHandle= 0;

            Lock.AcquireMutex();

            object obj = SourcesLookupTable[source.SourceName];

            if (obj != null) {

                sourceHandle = (UIntPtr)obj;
            }
            
            if (sourceHandle != 0) {

                object existingSource = SourcesHandleTable[sourceHandle];

                if (existingSource != null) {
                    
                    // Type already registered. Return the existing value
                    Lock.ReleaseMutex();
                    return false;
                }
            } else {

                // The handle for this source has not been allocated
                // Register a new one

                sourceHandle = AllocateSourceHandleImpl(source.SourceName);
                
                while (sourceHandle == 0) {

                    if (!TypesRepository.AddBuffer(BUFFER_EXPANSION_SIZE)) {

                        Lock.ReleaseMutex();
                        return false;
                    }

                    sourceHandle = AllocateSourceHandleImpl(source.SourceName);
                }

                SourcesLookupTable[source.SourceName] = sourceHandle;
            }

            // We must have here a valid source handle

            source.SourceHandle = sourceHandle;
            SourcesHandleTable[sourceHandle] = source;

            ActiveSource activeSource = source as ActiveSource;

            if (activeSource == null) {

                //  regular sources with associated memory storage

                RegisterSourceStorageImpl(sourceHandle, 
                                          source.Storage.GetHandle(), 
                                          source.ControlFlags);
                
            } else {

                RegisterActiveSourceImpl(sourceHandle, 
                                         activeSource.EventTypeHandle,
                                         activeSource.DebugBufferAddress,
                                         activeSource.Count,
                                         activeSource.EntrySize);

                //  Active sources, the object does the event buffer management
            }

            Lock.ReleaseMutex();
            return true;
        }
        
        public override void UnRegisterSource(EventSource source)
        {
            if (!Controller.Finalized) {
                Lock.AcquireMutex();
                
                if (source.SourceHandle != 0) {

                    SourcesHandleTable.Remove(source.SourceHandle);
                    UnRegisterSourceImpl(source.SourceHandle);

                    source.SourceHandle = 0;
                }
                Lock.ReleaseMutex();
            }
        }
        public override int QuerySourcesList(UIntPtr [] buffer, int size)
        {
            int i = 0;
            Lock.AcquireMutex();

            IDictionaryEnumerator enumerator = SourcesHandleTable.GetEnumerator();
            while (enumerator.MoveNext()) {

                if (i < size) {

                    EventSource source = enumerator.Value as EventSource;
                    buffer[i++] = source.SourceHandle;
                }
            }

            Lock.ReleaseMutex();
            return i;
        }

        public override int QueryEventTypeList(UIntPtr [] buffer, int size)
        {
            int i = 0;
            Lock.AcquireMutex();

            IDictionaryEnumerator enumerator = EventTable.GetEnumerator();
            while (enumerator.MoveNext()) {

                if (i < size) {

                    UIntPtr eventHandle = (UIntPtr)enumerator.Value;
                    buffer[i++] = eventHandle;
                }
            }

            Lock.ReleaseMutex();
            return i;
        }

        public override bool GetSourceInformation(UIntPtr sourceHandle,
                                                    ref UIntPtr storageHandle,
                                                    ref UIntPtr eventType,
                                                    ref UInt16 count,
                                                    ref string bufferName)
        {
            Lock.AcquireMutex();

            EventSource source = SourcesHandleTable[sourceHandle] as EventSource;

            if (source != null) {

                bufferName = source.SourceName;
                ActiveSource activeSource = source as ActiveSource;

                if (activeSource != null) {

                    storageHandle = 0;
                    eventType = activeSource.EventTypeHandle;
                    count = activeSource.Count;
                    
                } else {
                    storageHandle = source.Storage.GetHandle();
                    eventType = 0;
                    count = 0;
                }
                
                Lock.ReleaseMutex();

                return true;
            }
            
            Lock.ReleaseMutex();
            return false;
        }

        public override UIntPtr WalkEventDescriptor(UIntPtr eventHandle,
                                                    UIntPtr currentField,
                                                    ref UInt16 offset,
                                                    ref UInt16 type,
                                                    ref string bufferName)
        {
            UIntPtr fieldHandle = currentField;
            UInt16 tmpOffset;
            UInt16 tmpType;
            const UInt16 MaxBufferSize = 256;

            char[] tmpBufferName = new char[MaxBufferSize]; 

            unsafe {

                fixed(char* ptrBytes = &tmpBufferName[0]) {
                    
                    fieldHandle = MemoryStorage.WalkEventDescriptorImpl(eventHandle,
                                                                        fieldHandle,
                                                                        &tmpOffset,
                                                                        &tmpType,
                                                                        ptrBytes,
                                                                        MaxBufferSize);

                    if (fieldHandle != 0) {

                        string fieldName = "";

                        if (fieldName != null) {
                            for (int i = 0; i < MaxBufferSize; i++) {

                                if (tmpBufferName[i] == 0) {
                                    break;
                                }

                                fieldName += tmpBufferName[i];
                            }
                        }
                        type = tmpType;
                        offset = tmpOffset;
                        bufferName = fieldName;
                    }
                }
            }
            return fieldHandle;
        }

        public override bool QueryActiveEntry(UIntPtr sourceHandle,
                                             int index,
                                             ref QueryBuffer entryBuffer)
        {
            unsafe {

                UInt32 offset;
                UIntPtr type;
                
                fixed(byte * ptr = &(entryBuffer.GetBuffer()[0])) {

                    bool success = ReadActiveSourceItem(sourceHandle, index, &type, ptr, entryBuffer.GetBufferSize());


                    entryBuffer.Type = type;

                    // the active entries do not have any header

                    entryBuffer.UserOffset = 0;

                    return success;
                }
            }
        }

        public unsafe bool ReadActiveSourceItem(UIntPtr sourceHandle,
                                                        int item,
                                                        UIntPtr * type,
                                                        byte * buffer,
                                                        UInt16 bufferSize )
        {
            Lock.AcquireMutex();

            object source = SourcesHandleTable[sourceHandle];

            if (source != null) {
                ActiveSource activeSource =  source as ActiveSource;

                if (activeSource != null) {

                    bool success = activeSource.GetActiveEntry(item, type, buffer, bufferSize);
                    Lock.ReleaseMutex();

                    return success;
                }
            }
            
            Lock.ReleaseMutex();
            return false;
        }

        internal bool GetNativeSourceName(UIntPtr sourceHandle,
                                                   ref UIntPtr storageHandle,
                                                   ref string bufferName)
        {
            bool success = false;
            const UInt16 MaxBufferSize = 256;
            UIntPtr tmpHandle;

            char[] tmpBufferName = new char[MaxBufferSize]; 

            unsafe {

                fixed(char* ptrBytes = &tmpBufferName[0]) {

                    success = QueryNativeSourceInfo(sourceHandle, &tmpHandle, ptrBytes, MaxBufferSize);

                    if (success) {

                        string sourceName = "";

                        if (sourceName != null) {
                            for (int i = 0; i < MaxBufferSize; i++) {

                                if (tmpBufferName[i] == 0) {
                                    break;
                                }

                                sourceName += tmpBufferName[i];
                            }
                        }
                        bufferName = sourceName;
                        storageHandle = tmpHandle;
                    }
                }
            }
            return success;
        }

        // ABI interfaces

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe bool GetControllerHandle(UIntPtr * sourceHandle, UIntPtr * storageHandle);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe UIntPtr FetchLocalStorage();

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe bool SetRepositoryStorage(UIntPtr StorageHandle);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe UIntPtr RegisterEventDescriptorInternal(string eventName, 
                                                                            string eventDescription);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe UIntPtr RegisterEventFieldInternal(UIntPtr eventHandle,
                                                                       string fieldName,
                                                                       UInt16 offset,
                                                                       UInt16 type);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe UIntPtr RegisterEventGenericFieldInternal(UIntPtr eventHandle,
                                                                              string fieldName,
                                                                              UInt16 offset,
                                                                              UInt16 size,
                                                                              UIntPtr fieldTypeHandle);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe UIntPtr RegisterEnumDescriptorInternal(string enumName,
                                                                           UInt16 type);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe UIntPtr RegisterValueDescriptorInternal(UIntPtr enumHandle,
                                                                            string valueName,
                                                                            UInt64 value,
                                                                            byte flagChar);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe bool RegisterStorageImpl(UIntPtr StorageHandle);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe void UnRegisterStorageImpl(UIntPtr StorageHandle);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe UIntPtr AllocateSourceHandleImpl(string sourceName);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe void UnRegisterSourceImpl(UIntPtr sourceHandle);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe void RegisterSourceStorageImpl(UIntPtr sourceHandle, 
                                                                   UIntPtr storageHandle,
                                                                   UInt32 controlFlags);

        [AccessedByRuntime("output to header : defined in EventController.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe void RegisterActiveSourceImpl(UIntPtr sourceHandle, 
                                                                            UIntPtr eventTypeHandle,
                                                                            UIntPtr debuggerBufferAddress,
                                                                            UInt16 count,
                                                                            UInt16 entrySize);

        [AccessedByRuntime("output to header : defined in MemoryStorage.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe bool QueryNativeSourceInfo(UIntPtr sourceHandle,
                                                               UIntPtr * storageHandle, 
                                                               char * bufferName,
                                                               UInt16 bufferSize );

        [AccessedByRuntime("output to header : defined in MemoryStorage.cpp")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [StackBound(256)]
        [NoHeapAllocation]
        public static extern unsafe int QuerySystemSources(UIntPtr * sourceHandles,
                                                           UInt16 arraySize );
    }    

    //
    //  Event source for controller entries. Events and traces related
    //  to the controller's activity will use this source for logging
    //  For now, then only interesting event logged is the creation of
    //  the controller, which is helpful to associate a process name and ID with the
    //  current controller
    //
    
    [CLSCompliant(false)]
    public class ControllerLogger : EventSource {

        public static ControllerLogger Create(string sourceName, EventingStorage storage) {

            ControllerLogger Logger  = new ControllerLogger(sourceName, 
                                                            storage,
                                                            CAPTURE_STACK_TRACE | ENABLE_ALL_MASK);

            if (Logger != null) {

                Logger.Register();
            }

            return Logger;
        }

        ControllerLogger(string sourceName, EventingStorage storage, uint controlFlags) 
            :base(sourceName, storage, controlFlags) {}
      
    }
}

