using System;
using System.Diagnostics;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Windows.Threading;
using System.Threading.Tasks;
using System.Threading;
using System.Windows;
using System.Linq;
using System.Text;
using System.Windows.Data;
using MarketData.MarketDataModel;
using MarketData.DataAccess;
using MarketData.Utils;
using MarketData.Integration;
using MarketData;
using TradeBlotter.Command;
using TradeBlotter.ViewModels;
using TradeBlotter.Model;
using TradeBlotter.DataAccess;
using TradeBlotter.Cache;
using TradeBlotter.UIUtils;
using System.Windows.Media;
using Forms=System.Windows.Forms;
using MarketData.Numerical;
using System.Windows.Controls;
using Ticker.Animation;
using Ticker.Views;
using Ticker.Models;
using TradeBlotter.Views;
using System.Windows.Input;
using System.Configuration;

namespace TradeBlotter.ViewModels
{
  public class FloatingWindowViewModel : WorkspaceViewModel
  {
    private static int FLOATING_WINDOW_FEED_INTERVAL_MINUTES=1;  // This is the amount of time between feed pulls
    private readonly FeedManager manager = null;
    private Ticker<TickerItemView> ticker=null;
    private Panel mainPanel=null;
    private bool isPaused=false;
    private int itemCount=0;
    private RelayCommand togglePlayPausedCommand;
    private DateTime lastEarningsAnnouncementBroadcast;
    private DateTime lastAnalystRatingsBroadcast;
    private DateTime lastPremarketBroadcast;

    public FloatingWindowViewModel(Panel panel)
    {
      manager=new FeedManager();
      manager.FeedIntervalMinutes=FLOATING_WINDOW_FEED_INTERVAL_MINUTES;
      mainPanel=panel;
      ticker = new Ticker<TickerItemView>(mainPanel);
      ticker.ItemDisplayed += ticker_ItemDisplayed;
      manager.FeedSourceEventHandler+=GetFeedItemsEventHandler;
      manager.NewFeedItem+= (o,e)=>AddItem(e.Item);
      base.OnPropertyChanged("IsPaused");
      PropertyChanged += OnFloatingViewModelPropertyChanged;
      manager.Start();
      ticker.Start();
    }
    public override SaveParameters GetSaveParameters()
    {
      return null;
    }
    private void OnFloatingViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
      if (eventArgs.PropertyName.Equals("IsPaused"))
      {
        if(IsPaused && ticker.IsRunning)
        {
          ticker.Stop();
        }
        else if(!IsPaused && !ticker.IsRunning)
        {
          ticker.Start();
        }
      }
    }
// The feed does not persist contents between successive runs. It uses feed cache to filter previously displayed items for the day
    public override void SetSaveParameters(SaveParameters saveParameters)
    {
    }
    public override bool CanPersist()
    {
      return false;
    }
//*****************************************************************************************************************************************************************************
    private void AddItem(FeedItem item)
    {
      Application.Current.Dispatcher.Invoke((Forms.MethodInvoker)delegate()
      {
        ticker.Items.Enqueue(new TickerItemView(item));
      });
    }
    public String ItemCount
    {
      get{return itemCount.ToString();}
      set{itemCount=int.Parse(value);base.OnPropertyChanged("ItemCount");}
    }
    public bool IsPaused
    {
      get{return isPaused;}
      set{isPaused=value;base.OnPropertyChanged("IsPaused");}
    }
    public ICommand TogglePlayPauseCommand
    {
      get
      {
        if (togglePlayPausedCommand == null)
        {
          togglePlayPausedCommand = new RelayCommand(action => {IsPaused=!IsPaused;},action => { return true; });
        }
        return togglePlayPausedCommand;
      }
    }
    private void ticker_ItemDisplayed(object sender, ItemEventArgs<TickerItemView> e)
    {
      manager.MarkFeedAsRead(e.Item.FeedItem);
      itemCount=manager.GetFeedItemCount();
      base.OnPropertyChanged("ItemCount");
    }
    public List<FeedItem> GetFeedItemsEventHandler()
    {
      bool itemsAdded=false;
      List<FeedItem> feedItems=new List<FeedItem>();
      List<String> openSymbols=new List<String>();

      List<FeedItem> holidayStatusFeedItems=HolidayStatusToFeedItems();
      if(null!=holidayStatusFeedItems){feedItems.AddRange(holidayStatusFeedItems);itemsAdded=holidayStatusFeedItems.Count>0?true:itemsAdded;}
      
      List<FeedItem> networkStatusFeedItems=NetworkStatusToFeedItems();
      if(null!=networkStatusFeedItems){feedItems.AddRange(networkStatusFeedItems);itemsAdded=networkStatusFeedItems.Count>0?true:itemsAdded;}

      if((Utility.IsEpoch(lastPremarketBroadcast)||DateTime.Now-lastPremarketBroadcast>new TimeSpan(0,5,0)))   // earnings broadcast every 5 minutes
      {
        lastPremarketBroadcast=DateTime.Now;
        List<FeedItem> premarketFeedItems=PremarketToFeedItems();
        if(null!=premarketFeedItems) { feedItems.AddRange(premarketFeedItems); itemsAdded=premarketFeedItems.Count>0?true:itemsAdded; }
      }

      List<FeedItem> headlineFeedItems=HeadlinesToFeedItems();
      if(null!=headlineFeedItems){feedItems.AddRange(headlineFeedItems);itemsAdded=headlineFeedItems.Count>0?true:itemsAdded;}

      try{openSymbols=PortfolioDA.GetOpenSymbols();}catch(Exception){;}
      List<FeedItem> openPricesFeedItems=OpenPricesToFeedItems(openSymbols);
      if(null!=openPricesFeedItems){feedItems.AddRange(openPricesFeedItems);itemsAdded=openPricesFeedItems.Count>0?true:itemsAdded;}

      if(Utility.IsEpoch(lastAnalystRatingsBroadcast)||DateTime.Now-lastAnalystRatingsBroadcast>new TimeSpan(0,20,0))   // analyst ratings broadcast every 20 minutes
      {
        lastAnalystRatingsBroadcast=DateTime.Now;
        List<FeedItem> analystRatingsFeedItems=AnalystRatingsToFeedItems(openSymbols);
        if(null!=analystRatingsFeedItems){feedItems.AddRange(analystRatingsFeedItems);itemsAdded=analystRatingsFeedItems.Count>0?true:itemsAdded;}
      }

      if(Utility.IsEpoch(lastEarningsAnnouncementBroadcast)||DateTime.Now-lastEarningsAnnouncementBroadcast>new TimeSpan(0,20,0))   // earnings broadcast every 20 minutes
      {
        lastEarningsAnnouncementBroadcast=DateTime.Now;
        List<FeedItem> earningsAnnouncementFeedItems=EarningsAnnouncementsToFeedItems(openSymbols);
        if(null!=earningsAnnouncementFeedItems){feedItems.AddRange(earningsAnnouncementFeedItems);itemsAdded=earningsAnnouncementFeedItems.Count>0?true:itemsAdded;}
      }
      return feedItems;
    }
// ***************************************************************************************************************************************************
// ************************************************************************ F E E D  C O N V E R T E R S  ********************************************
// ***************************************************************************************************************************************************
    private List<FeedItem> NetworkStatusToFeedItems()
    {
      List<FeedItem> feedItems=new List<FeedItem>();

      try
      {
        //if(NetworkStatus.IsNetworkAvailable())return null;
        if(NetworkStatus.IsInternetConnected())return null;
        FeedItem feedItem=new FeedItem();
        feedItem.Description="Network is unavailable";
        feedItem.Title=String.Format("Network is unavailable");
        feedItem.Link="http://192.168.1.1/"; 
        feedItem.Source="Network";
        feedItem.PubDate=DateTime.Now.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now);
        feedItem.Guid="Network"+feedItem.PubDate;
        feedItem.BrushAssigment=FeedBrushes.BrushColor.Red;
        feedItems.Add(feedItem);
        return feedItems;
      }
      catch(Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
        return null;
      }
    }

    private List<FeedItem> HolidayStatusToFeedItems()
    {
      List<FeedItem> feedItems=new List<FeedItem>();

      try
      {
        DateTime today=DateTime.Now.Date;
        DateGenerator dateGenerator = new DateGenerator();
        if(!dateGenerator.IsHoliday(today.Date))return feedItems;
        String holidayDescription = HolidayDA.GetHolidayDescription(today);

        FeedItem feedItem=new FeedItem();
        feedItem.Description="Market is closed today - "+holidayDescription+".";
        feedItem.Title=String.Format("Market is closed today for "+holidayDescription+".");
        feedItem.Link="http://192.168.1.1/"; 
        feedItem.Source="Holiday";
        feedItem.PubDate=DateTime.Now.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now);
        feedItem.Guid="Holiday"+feedItem.PubDate;
        feedItem.BrushAssigment=FeedBrushes.BrushColor.Red;
        feedItems.Add(feedItem);
        return feedItems;
      }
      catch(Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
        return null;
      }
    }

    private List<FeedItem> PremarketToFeedItems()
    {
      List<FeedItem> feedItems=new List<FeedItem>();

      try
      {
        String tickerPremarketFeedIdleAfter=ConfigurationManager.AppSettings["TickerPremarketFeedIdleAfter"]; 
        if(null==tickerPremarketFeedIdleAfter)tickerPremarketFeedIdleAfter="09:30:00";
        TimeSpan cutoff=TimeSpan.Parse(tickerPremarketFeedIdleAfter);
        if(DateTime.Now.TimeOfDay>cutoff)return feedItems;
        PremarketElements premarketElements=PremarketDA.GetLatestPremarketData();
        if(null==premarketElements||0==premarketElements.Count)return feedItems;
        foreach(PremarketElement premarketElement in  premarketElements)
        {
          FeedItem feedItem=new FeedItem();
          feedItem.Description=premarketElement.Market;
          feedItem.Title=String.Format("{0} {1}({2})",premarketElement.Market,Utility.FormatNumber(premarketElement.ChangeValue,2),Utility.FormatPercent(premarketElement.ChangePercent/100.00));
          feedItem.Link="https://money.cnn.com/data/premarket//";
          feedItem.Source="CNN";
          feedItem.PubDate=premarketElement.Timestamp.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(premarketElement.Timestamp);
          feedItem.Guid=premarketElement.Market+feedItem.PubDate;
          if(premarketElement.ChangePercent<0)feedItem.BrushAssigment=FeedBrushes.BrushColor.Red;
          else feedItem.BrushAssigment=FeedBrushes.BrushColor.Green; 
          feedItems.Add(feedItem);
        }
        return feedItems;
      }
      catch(Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
        return null;
      }
    }
    private List<FeedItem> EarningsAnnouncementsToFeedItems(List<String> openSymbols)
    {
      List<FeedItem> feedItems=new List<FeedItem>();
      int maxDaysFromToday=2;

      try
      {
        DateTime today=DateTime.Now;
        String tickerEarningsAnnouncementMaxDays=ConfigurationManager.AppSettings["TickerEarningsAnnouncementMaxDays"];
        if(null!=tickerEarningsAnnouncementMaxDays)int.TryParse(tickerEarningsAnnouncementMaxDays,out maxDaysFromToday);
        List<EarningsAnnouncementModel> earningsAnnouncementModels = new List<EarningsAnnouncementModel>();
        List<String> symbols = WatchListDA.GetWatchList("valuations");
        foreach (String symbol in symbols)
        {
          EarningsAnnouncementModel earningsAnnouncementModel=CompositeDA.GetEarningsAnnouncement(symbol);
          if(null==earningsAnnouncementModel)continue;
          if (earningsAnnouncementModel.DaysFromToday > maxDaysFromToday || earningsAnnouncementModel.DaysFromToday<0) continue;
          earningsAnnouncementModels.Add(earningsAnnouncementModel);
        }
        earningsAnnouncementModels.Sort();
        foreach(EarningsAnnouncementModel earningsAnnouncementModel in earningsAnnouncementModels)
        {
          int days=Math.Abs(earningsAnnouncementModel.DaysFromToday);
          FeedItem feedItem=new FeedItem();
          feedItem.Description=earningsAnnouncementModel.Symbol;
          if(0==days)feedItem.Title=String.Format("Earnings Annoucement for {0} due today",earningsAnnouncementModel.Symbol);
          else feedItem.Title=String.Format("Earnings Annoucement for {0} due in {1} {2} ",earningsAnnouncementModel.Symbol,days,days>1?"days":"day");;
          feedItem.Link="https://www.zacks.com/stock/research/"+earningsAnnouncementModel.Symbol+"/earnings-announcements"; 
          feedItem.Source="Earnings Announcements";
          feedItem.PubDate=today.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now);
          feedItem.Guid="Earnings Announcement "+earningsAnnouncementModel.Symbol+" "+today+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now);
          if(openSymbols.Any(x=>x.Equals(earningsAnnouncementModel.Symbol)))feedItem.BrushAssigment=FeedBrushes.BrushColor.Red;
          feedItems.Add(feedItem);
        }
        return feedItems;
      }
      catch(Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
        return feedItems;
      }
    }
    private List<FeedItem> AnalystRatingsToFeedItems(List<String> openSymbols)
    {
      List<FeedItem> feedItems=new List<FeedItem>();
      List<String> watchListSymbols = WatchListDA.GetWatchList("valuations");
      if(null==watchListSymbols)watchListSymbols=new List<String>();
      if(null==openSymbols)openSymbols=new List<String>();
      try
      {
        DateTime today=DateTime.Now;
        AnalystRatings analystRatings=AnalystRatingsDA.GetAnalystRatings(today);
        foreach(AnalystRating analystRating in analystRatings)
        {
          if(!openSymbols.Any(x=>x.Equals(analystRating.Symbol)) && !watchListSymbols.Any(x=>x.Equals(analystRating.Symbol)))continue;
          StringBuilder sb=new StringBuilder();
          FeedItem feedItem=new FeedItem();
          sb.Append(analystRating.Symbol).Append("(").Append(analystRating.Type).Append(")").Append(":").Append(analystRating.RatingsChange);
          if(0.00!=analystRating.PriceTarget)sb.Append(":").Append(Utility.FormatCurrency(analystRating.PriceTarget));
          String lineData=sb.ToString();
          feedItem.Description=analystRating.Symbol;
          feedItem.Title=lineData;
          feedItem.Link="https://www.google.com/search?q="+Uri.EscapeDataString(analystRating.Symbol)+"/";
          feedItem.Source="Analyst Ratings";
          feedItem.PubDate=today.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now);
          feedItem.Guid="Analyst Ratings"+analystRating.Symbol+" "+today+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now);;
          if(openSymbols.Any(x=>x.Equals(analystRating.Symbol)&&analystRating.Type.Equals("Downgrades")))feedItem.BrushAssigment=FeedBrushes.BrushColor.Red;
          else if(openSymbols.Any(x=>x.Equals(analystRating.Symbol)&&analystRating.Type.Equals("Upgrades"))) feedItem.BrushAssigment=FeedBrushes.BrushColor.Green;
          feedItems.Add(feedItem);
        }
        return feedItems;
      }
      catch(Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
        return feedItems;
      }
    }
    private List<FeedItem> OpenPricesToFeedItems(List<String> openSymbols)
    {
      List<FeedItem> feedItems=new List<FeedItem>();
      try
      {
        DateTime pricingDate=DateTime.Now;
        DateGenerator dateGenerator=new DateGenerator();
        foreach(String symbol in openSymbols)
        {
          Price todaysPrice=PricingDA.GetPrice(symbol);
          if(null==todaysPrice)continue;
          DateTime prevDate=dateGenerator.FindPrevBusinessDay(todaysPrice.Date);
          Price prevPrice=PricingDA.GetPrice(symbol,prevDate);
          if(null==prevPrice)continue;
          double change=(todaysPrice.Close-prevPrice.Close)/prevPrice.Close;
          String strPercentChange=Utility.FormatPercent(change);
          FeedItem feedItem=new FeedItem();
          feedItem.Description=symbol;
          feedItem.Title=symbol+":"+strPercentChange;
          feedItem.Link="https://www.google.com/search?q="+Uri.EscapeDataString(symbol)+"/";
          feedItem.Source="Price Feed";
          feedItem.PubDate=todaysPrice.Date.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now);
          feedItem.Guid=symbol+todaysPrice.Date.ToShortDateString()+":"+strPercentChange;
          if(change<0)feedItem.BrushAssigment=FeedBrushes.BrushColor.Red;
          else if(change>0)feedItem.BrushAssigment=FeedBrushes.BrushColor.Green;
          else feedItem.BrushAssigment=FeedBrushes.BrushColor.Normal;
          feedItems.Add(feedItem);
        }
        return feedItems;
      }
      catch(Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
        return feedItems;
      }
    }
    private List<FeedItem> HeadlinesToFeedItems()
    {
      List<FeedItem> feedItems=new List<FeedItem>();
      try
      {
        DateTime today=DateTime.Now;
        MarketData.MarketDataModel.Headlines headlines=HeadlinesDA.GetHeadlines(today);
        for(int index=0;index<headlines.Count;index++)
        {
          MarketData.MarketDataModel.Headline headline=headlines[index];
          FeedItem feedItem=new FeedItem();
          feedItem.Description=headline.Entry;
          feedItem.Title=headline.Symbol+":"+headline.Entry;
          feedItem.Link="https://www.google.com/search?q="+Uri.EscapeDataString(headline.Entry)+"/";
          feedItem.Source=headline.Source;
          feedItem.PubDate=headline.Date.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(headline.Modified);
          feedItem.Guid=headline.Symbol+headline.Date.ToShortDateString()+":"+Utility.DateTimeToStringHHMMSS(headline.Modified)+":"+headline.Entry;
          feedItems.Add(feedItem);
        }
        return feedItems;
      }
      catch(Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
        return feedItems;
      }
    }
    public virtual void Dispose()
    {
      if(null!=ticker)ticker.Stop();
      if(null!=manager)manager.Dispose();
    }
  }
}
