/*++
Copyright (c) 2015 Microsoft Corporation
--*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.Z3;
namespace Microsoft.SolverFoundation.Plugin.Z3
{
    /// 
    /// Thread that will wait until the query abort function returns true or 
    /// the stop method is called. If the abort function returns true at some
    /// point it will issue a softCancel() call to Z3.
    /// 
    internal class AbortWorker
    {
        #region Private Members
        /// The Z3 solver
        private Microsoft.Z3.Context _context;
        /// The abort function to use to check if we are aborted
        private Func _QueryAbortFunction;
        /// Flag indicating that worker should stop
        private bool _stop = false;
        /// Flag indicating that we have been sent an abort signal
        private bool _aborted = false;
        #endregion Private Members
        #region Construction
        /// 
        /// Worker constructor taking a Z3 instance and a function to periodically
        /// check for aborts.
        /// 
        /// Z3 instance
        /// method to call to check for aborts
        public AbortWorker(Context context, Func queryAbortFunction)
        {
            _context = context;
            _QueryAbortFunction = queryAbortFunction;
        }
        #endregion Construction
        #region Public Methods
        /// 
        /// Stop the abort worker.
        /// 
        public void Stop()
        {
            _stop = true;
        }
        /// 
        /// Is true if we have been aborted.
        /// 
        public bool Aborted
        {
            get
            {
                return _aborted;
            }
        }
        /// 
        /// Starts the abort worker. The worker checks the abort method
        /// periodically until either it is stopped by a call to the Stop()
        /// method or it gets an abort signal. In the latter case it will
        /// issue a soft abort signal to Z3.
        /// 
        public void Start()
        {
            // We go until someone stops us
            _stop = false;
            while (!_stop && !_QueryAbortFunction())
            {
                // Wait for a while
                Thread.Sleep(10);
            }
            // If we were stopped on abort, cancel z3
            if (!_stop)
            {
                _context.Interrupt();
                _aborted = true;
            }
        }
        #endregion Public Methods
    }
}