using System;
using System.Collections.Generic;
using System.Text;
using Weborb.Messaging.Server.Adapter;
using Weborb.Messaging.Api.Service;
using System.Timers;
using Weborb.Messaging.Api;
using Weborb.Messaging.Server;
using System.Diagnostics;
using System.Collections;
using Weborb.Util.Logging;

namespace Weborb.Management.Monitoring.Performance
{
    public class AppHandler : ApplicationAdapter, IPendingServiceCallback
    {
        Timer timer = new Timer();
        Dictionary<IConnection, Subscription> subscribers;
        Dictionary<String, PerformanceCounter> counters;

        public AppHandler()
        {
            timer.Interval = 100;
            timer.Elapsed += new ElapsedEventHandler( OnTimer );
            subscribers = new Dictionary<IConnection, Subscription>();
            counters = new Dictionary<string, PerformanceCounter>();
            timer.Start();
        }

        void OnTimer( object sender, ElapsedEventArgs e )
        {
            lock( subscribers )
            {
                foreach( IConnection connection in subscribers.Keys )
                {
                    Hashtable countersValue = new Hashtable();
                    Subscription subscription = subscribers[ connection ];

                    if( subscription.NextEventTime > DateTime.Now )
                        continue;

                    foreach( String counterName in subscription.Counters )
                    {
                        PerformanceCounter performanceCounter = counters[ counterName ];
                        countersValue[ counterName ] = performanceCounter.NextValue();
                    }

                    subscription.NextEventTime = subscription.NextEventTime.AddMilliseconds( subscription.UpdateFrequency );

                    if( countersValue.Count == 0 )
                        continue;

                    ((IServiceCapableConnection)connection).invoke( "CountersUpdated", new object[] { countersValue } );
                }
            }
        }

        public override void appDisconnect( IConnection conn )
        {
            lock( subscribers )
            {
                subscribers.Remove( conn );
            }
        }

        public List<String> getCounterCategories()
        {
            List<String> counterCategoryList = new List<String>();

            foreach( PerformanceCounterCategory performanceCounterCategory in PerformanceCounterCategory.GetCategories() )
                counterCategoryList.Add( performanceCounterCategory.CategoryName );

            counterCategoryList.Sort( delegate( String l, String r ){ return l.CompareTo( r ); } );
            return counterCategoryList;
        }

        public CounterCategory getCategoryCounters( String categoryName )
        {
            foreach( PerformanceCounterCategory performanceCounterCategory in PerformanceCounterCategory.GetCategories() )
            {
                if( !performanceCounterCategory.CategoryName.Equals( categoryName ) )
                    continue;

                CounterCategory counterCategory = new CounterCategory( performanceCounterCategory );

                if( performanceCounterCategory.CategoryType == PerformanceCounterCategoryType.SingleInstance )
                {
                    List<Counter> counters = new List<Counter>();

                    foreach( PerformanceCounter performanceCounter in performanceCounterCategory.GetCounters() )
                        counters.Add( new Counter( performanceCounter ) );

                    counters.Sort( delegate( Counter l, Counter r ) { return l.Name.CompareTo( r.Name ); } );
                    counterCategory.Counters[ "SingleInstance" ] = counters;
                    counterCategory.IsMultiInstance = false;
                }
                else
                {
                    foreach( String instanceName in performanceCounterCategory.GetInstanceNames() )
                    {
                        List<Counter> counters = new List<Counter>();

                        foreach( PerformanceCounter performanceCounter in performanceCounterCategory.GetCounters( instanceName ) )
                            counters.Add( new Counter( performanceCounter ) );

                        counters.Sort( delegate( Counter l, Counter r ) { return l.Name.CompareTo( r.Name ); } );
                        counterCategory.Counters[ instanceName ] = counters;
                        counterCategory.IsMultiInstance = true;
                    }
                }

                return counterCategory;
            }

            throw new Exception( "category cannot be found - " + categoryName );
        }

        public String subscribe( String categoryName, String instance, String counterName )
        {
            IConnection currentConnection = ConnectionHub.getConnectionLocal();

            lock( subscribers )
            {
                if( !subscribers.ContainsKey( currentConnection ) )
                    subscribers.Add( currentConnection, new Subscription() );
            }

            String key = categoryName + "." + instance + "." + counterName;

            if( !counters.ContainsKey( key ) )
            {
                PerformanceCounter performanceCounter = null;

                foreach( PerformanceCounterCategory performanceCounterCategory in PerformanceCounterCategory.GetCategories() )
                {
                    if( performanceCounterCategory.CategoryName == categoryName )
                    {
                        if( performanceCounterCategory.CategoryType == PerformanceCounterCategoryType.MultiInstance
                               && !performanceCounterCategory.InstanceExists( instance ) )
                            throw new Exception( "Invalid instance name" );

                        if( !performanceCounterCategory.CounterExists( counterName ) )
                            throw new Exception( "Invalid counter name" );

                        if( performanceCounterCategory.CategoryType == PerformanceCounterCategoryType.MultiInstance )
                            performanceCounter = new PerformanceCounter( performanceCounterCategory.CategoryName, counterName, instance );
                        else
                            performanceCounter = new PerformanceCounter( performanceCounterCategory.CategoryName, counterName );

                        break;
                    }
                }

                if( performanceCounter == null )
                    throw new Exception( "Invalid category name" );

                lock( counters )
                {
                    counters.Add( key, performanceCounter );
                }
            }

            lock( subscribers )
            {
                if( !subscribers[ currentConnection ].Counters.Contains( key ) )
                    subscribers[ currentConnection ].Counters.Add( key );
            }

            return key;
        }

        public String unsubscribe( String key )
        {
            IConnection currentConnection = ConnectionHub.getConnectionLocal();

            if( !subscribers.ContainsKey( currentConnection ) )
                return String.Empty;

            lock( subscribers )
            {
                subscribers[ currentConnection ].Counters.Remove( key );
            }

            return key;
        }

        public void changeFrequence( int ms )
        {
            IConnection currentConnection = ConnectionHub.getConnectionLocal();

            lock( subscribers )
            {
                if( !subscribers.ContainsKey( currentConnection ) )
                    subscribers.Add( currentConnection, new Subscription() );
            }

            subscribers[ currentConnection ].UpdateFrequency = ms;
            subscribers[ currentConnection ].NextEventTime = DateTime.Now.AddMilliseconds( ms );
        }

        #region IPendingServiceCallback Members

        public void resultReceived( IPendingServiceCall call )
        {

        }

        #endregion
    }
}