/// <summary>
        /// Callback on insert of Watson results - using the transaction submitted but NOT committed
        ///
        /// For each action, use the most likely sentiment (highest SentimentScore)
        /// Use Net Promoter score (promoters - detractors), normalized to [0, 1000] where 500 is neutral
        /// </summary>
        /// <param name="transaction">data associated with the watson transaction</param>
        public static void TicketSentimentStrategy(DataContext db, ActionToAnalyze actionToAnalyze, ActionSentimentScore maxScore)
        {
            if (actionToAnalyze.IsAgent)
            {
                return;
            }

            try
            {
                // normalize to [0, 1000]
                double actionScore = Convert.ToDouble(ToneSentiment.ToneSentiments[maxScore.SentimentID].SentimentMultiplier.Value) * Convert.ToDouble(maxScore.SentimentScore);
                actionScore = 500 * actionScore + 500;

                // submit TicketSentiment
                TicketSentiment score = null;
                CreateTicketSentiment(db, actionToAnalyze, actionScore, out score);
                score.TicketSentimentScore = (int)Math.Round(score.AverageActionSentiment);
                score.SetSentimentID(maxScore.SentimentID);
                db.SubmitChanges();
            }
            catch (Exception e2)
            {
                WatsonEventLog.WriteEntry("Exception caught at select from ACtionsToAnalyze or HttpPOST:", e2);
                Console.WriteLine(e2.ToString());
            }
        }
        static bool CreateTicketSentiment(DataContext db, ActionToAnalyze actionToAnalyze, double actionScore, out TicketSentiment score)
        {
            Table <TicketSentiment> table = db.GetTable <TicketSentiment>();

            score = table.Where(t => (t.TicketID == actionToAnalyze.TicketID) && (t.IsAgent == actionToAnalyze.IsAgent)).FirstOrDefault();
            if (score == null)
            {
                score = new TicketSentiment()
                {
                    TicketID             = actionToAnalyze.TicketID,
                    OrganizationID       = actionToAnalyze.OrganizationID,
                    IsAgent              = actionToAnalyze.IsAgent,
                    TicketDateCreated    = actionToAnalyze.DateCreated,
                    TicketSentimentScore = 0,
                    Sad                    = false,
                    Frustrated             = false,
                    Satisfied              = false,
                    Excited                = false,
                    Polite                 = false,
                    Impolite               = false,
                    Sympathetic            = false,
                    AverageActionSentiment = actionScore,
                    ActionSentimentCount   = 1
                };
                table.InsertOnSubmit(score);
                return(true);
            }
            return(false);
        }
        public void DoRebuild()
        {
            try
            {
                string connectionString = ConfigurationManager.AppSettings.Get("ConnectionString");
                using (SqlConnection connection = new SqlConnection(connectionString))
                    using (DataContext db = new DataContext(connection))
                    {
                        db.ObjectTrackingEnabled = false; // read-only linq to sql

                        Initialize(db);

                        // load the highest confidence sentiment for each client action
                        MaxActionSentiment[] actionSentiments = LoadActionSentiments(db);
                        Array.Sort(actionSentiments, (lhs, rhs) => lhs.TicketID.CompareTo(rhs.TicketID));
                        foreach (MaxActionSentiment actionSentiment in actionSentiments)
                        {
                            // new TicketSentiment?
                            double actionScore = ToTicketScore(actionSentiment.SentimentID, actionSentiment.MaxSentimentScore);
                            if (!_ticketSentiments.ContainsKey(actionSentiment.TicketID))
                            {
                                _ticketSentiments[actionSentiment.TicketID] = CreateTicketSentiment(actionSentiment, db, actionScore);
                                continue;
                            }

                            // update existing TicketSentiment
                            TicketSentiment sentiment = _ticketSentiments[actionSentiment.TicketID];
                            int             count     = sentiment.ActionSentimentCount;
                            sentiment.AverageActionSentiment = (count * sentiment.AverageActionSentiment + actionScore) / (count + 1);
                            sentiment.ActionSentimentCount   = count + 1;
                            sentiment.TicketSentimentScore   = (int)Math.Round(sentiment.AverageActionSentiment);
                            sentiment.SetSentimentID(actionSentiment.SentimentID);
                        }

                        int insertCount = 0;
                        foreach (KeyValuePair <int, TicketSentiment> pair in _ticketSentiments)
                        {
                            pair.Value.Insert(db);
                            if (++insertCount >= 1000)
                            {
                                Console.Write('.');
                                insertCount = 0;
                            }
                        }
                    }
            }
            catch (Exception e)
            {
                WatsonEventLog.WriteEntry("Exception in RebuildTicketSentimentsTable", e);
                Console.WriteLine(e.ToString());
            }
        }
        /// <summary>
        /// first action sentiment creates the ticket sentiment
        /// </summary>
        TicketSentiment CreateTicketSentiment(MaxActionSentiment actionSentiment, DataContext db, double actionScore)
        {
            TicketSentiment ticketSentiment = new TicketSentiment()
            {
                TicketID             = actionSentiment.TicketID,
                OrganizationID       = actionSentiment.OrganizationID,
                IsAgent              = actionSentiment.IsAgent,
                TicketDateCreated    = actionSentiment.DateCreated,
                TicketSentimentScore = (int)Math.Round(actionScore),
                Sad                    = false,
                Frustrated             = false,
                Satisfied              = false,
                Excited                = false,
                Polite                 = false,
                Impolite               = false,
                Sympathetic            = false,
                AverageActionSentiment = actionScore,
                ActionSentimentCount   = 1
            };

            ticketSentiment.SetSentimentID(actionSentiment.SentimentID);
            return(ticketSentiment);
        }
        public void RecordWatsonResults(ActionToAnalyze actionToAnalyze)
        {
            // insert ActionSentiment
            ActionSentiment sentiment = InsertActionSentiment(_db, actionToAnalyze);

            _db.SubmitChanges();    // get the DB generated ID
            int actionSentimentID = sentiment.ActionSentimentID;

            // insert child records - ActionSentimentScore(s)
            List <Tones> tones = actionToAnalyze.GetTones();
            List <ActionSentimentScore> scores = InsertSentimentScores(tones, _db, actionSentimentID);

            // update the corresponding ticket sentiment
            if (!actionToAnalyze.IsAgent)
            {
                ActionSentimentScore maxScore = scores.Where(s => s.SentimentScore == scores.Max(a => a.SentimentScore)).First();
                TicketSentiment.TicketSentimentStrategy(_db, actionToAnalyze, maxScore);
            }

            // Delete ActionToAnalyze
            actionToAnalyze.DeleteOnSubmit(_db);
            _db.SubmitChanges();
        }