<[email protected]>
<http://www.gnu.org/licenses/>
#ifndef WSORTVIEW_H
#define WSORTVIEW_H
#include <wx/wx.h>
#include <wx/thread.h>
#include <wx/log.h>
#include <vector>
#include <algorithm>
#define ASSERT(cond) do { if (!(cond)) {                \
    wxLogError(_("Assertion failed:\n%s in %s:%d"),     \
               _T(#cond), _T(__FILE__), __LINE__);      \
    wxLog::FlushActive();                               \
    abort();                                            \
} } while(0)
extern bool g_sound_on;
extern double g_sound_sustain;
void SoundCallback(void *udata, unsigned char *stream, int len);
void SoundReset();
void SoundAccess(size_t i);
extern size_t       g_compare_count;
extern size_t       g_access_count;
class ArrayItem
{
public:
    typedef int value_type;
protected:
    value_type     value;
public:
    ArrayItem() {}
    explicit ArrayItem(const value_type& d) : value(d) {}
    ArrayItem(const ArrayItem& v) : value(v.value) {}
    
    
    
    const value_type& get() const
    { OnAccess(*this); return value; }
    static void OnAccess(const ArrayItem& a);
    
    const value_type& get_direct() const
    { return value; }
    
    bool operator== (const ArrayItem& v) const
    { OnComparison(*this,v); return (value == v.value); }
    bool operator!= (const ArrayItem& v) const
    { OnComparison(*this,v); return (value != v.value); }
    bool operator< (const ArrayItem& v) const
    { OnComparison(*this,v); return (value < v.value); }
    bool operator<= (const ArrayItem& v) const
    { OnComparison(*this,v); return (value <= v.value); }
    bool operator> (const ArrayItem& v) const
    { OnComparison(*this,v); return (value > v.value); }
    bool operator>= (const ArrayItem& v) const
    { OnComparison(*this,v); return (value >= v.value); }
    
    int cmp(const ArrayItem& v) const
    { OnComparison(*this,v); return (value == v.value ? 0 : value < v.value ? -1 : +1); }
    
    bool equal_direct(const ArrayItem& v) const
    { return (value == v.value); }
    bool less_direct(const ArrayItem& v) const
    { return (value < v.value); }
    bool greater_direct(const ArrayItem& v) const
    { return (value > v.value); }
    static void OnComparison(const ArrayItem& a, const ArrayItem& b);
};
extern double g_delay;
extern bool g_algo_running;
extern wxString g_algo_name;
class WSortView : public wxPanel
{
public:
    WSortView(wxWindow *parent, int id, class WMain_wxg* wmain);
    ~WSortView();
    class WMain*        wmain;
    void                RepaintNow();
    virtual void	OnPaint(wxPaintEvent& pe);
    virtual void	OnSize(wxSizeEvent& se);
    
    void                paint(wxDC& dc, const wxSize& dcsize);
public:
    DECLARE_EVENT_TABLE();
protected:
    
    
    std::vector<ArrayItem>     m_array;
    
    ArrayItem::value_type      m_array_max;
    
    bool m_calc_inversions;
    
    ssize_t m_inversions;
    
    struct Access
    {
        unsigned int index;
        unsigned short color;
        unsigned short sustain;
        unsigned short priority;
        Access(size_t i=0, unsigned short c=1,
               unsigned short s=0, unsigned short p=0)
            : index(i), color(c), sustain(s), priority(p) { }
    };
    
    Access      m_access1, m_access2;
    
    std::vector<Access> m_access_list;
    
    wxMutex     m_mutex;
    
    std::vector<unsigned char>   m_mark;
    
    std::vector< std::pair<volatile ssize_t*,unsigned char> > m_watch;
    
    bool        m_is_sorted;
    
    bool        m_stepwise;
    
    wxSemaphore m_step_semaphore;
    
public:
    
    void OnAlgoLaunch(const struct AlgoEntry& ae);
    
    void ToggleCalcInversions();
    
    void FillData(unsigned int schema, size_t arraysize);
    
    void FillInputlist(wxControlWithItems* list);
    
    bool IsSorted() const { return m_is_sorted; }
    
    void CheckSorted();
    
    void SetStepwise(bool v) { m_stepwise = v; }
    
    void DoStepwise();
    
    ssize_t GetInversions() const
    { return m_inversions; }
    
    size_t GetRuns() const;
protected:
    
    void ResetArray(size_t size);
    
    void FinishFill();
    
    void OnAccess();
    
    void SaveAccess(size_t i);
    
    short InAccessList(ssize_t idx);
    
    unsigned short InWatchList(ssize_t idx) const;
    
    void RecalcInversions();
    
    void UpdateInversions(size_t i, size_t j);
public:
    
    size_t size() const { return m_array.size(); }
    
    const ArrayItem::value_type& array_max() const
    { return m_array_max; }
    
    void DoDelay(double delay);
    
    const ArrayItem& direct(size_t i) const
    {
        ASSERT(i < m_array.size());
        return m_array[i];
    }
    
    const ArrayItem& operator[](size_t i)
    {
        ASSERT(i < m_array.size());
        if (m_access1.index != i)
        {
            {
                wxMutexLocker lock(m_mutex);
                ASSERT(lock.IsOk());
                m_access1 = i;
                m_access_list.push_back(i);
            }
            
            OnAccess();
        }
        return m_array[i];
    }
    
    ArrayItem& get_mutable(size_t i)
    {
        ASSERT(i < m_array.size());
        if (m_access1.index != i)
        {
            {
                wxMutexLocker lock(m_mutex);
                ASSERT(lock.IsOk());
                m_access1 = i;
                m_access_list.push_back(i);
            }
            
            OnAccess();
        }
        RecalcInversions();
        return m_array[i];
    }
    
    const ArrayItem& get_nocount(size_t i)
    {
        ASSERT(i < m_array.size());
        if (m_access1.index != i)
        {
            {
                wxMutexLocker lock(m_mutex);
                ASSERT(lock.IsOk());
                m_access1 = i;
                m_access_list.push_back(i);
            }
            
            --g_access_count;
            OnAccess();
        }
        return m_array[i];
    }
    
    void set(size_t i, const ArrayItem& v)
    {
        ASSERT(i < m_array.size());
        {
            wxMutexLocker lock(m_mutex);
            ASSERT(lock.IsOk());
            m_access1 = i;
            m_access_list.push_back(i);
            m_array[i] = v;
        }
        RecalcInversions();
        OnAccess();
    }
    
    
    void swap(size_t i, size_t j)
    {
        ASSERT(i < m_array.size());
        ASSERT(j < m_array.size());
        {
            wxMutexLocker lock(m_mutex);
            ASSERT(lock.IsOk());
            m_access1 = i;
            m_access2 = j;
            m_access_list.push_back(i);
            m_access_list.push_back(j);
        }
        UpdateInversions(i, j); 
        OnAccess();
        std::swap(m_array[i], m_array[j]);
        OnAccess();
        m_access2 = -1;
    }
    
    void touch(size_t i, int color = 2,
               unsigned short sustain = 0, unsigned short priority = 0)
    {
        ASSERT(i < m_array.size());
        {
            wxMutexLocker lock(m_mutex);
            ASSERT(lock.IsOk());
            m_access1 = Access(i, color, sustain, priority);
            m_access_list.push_back( Access(i, color, sustain, priority) );
        }
    }
    
    void mark(size_t i, int color = 2)
    {
        ASSERT(i < m_array.size());
        m_mark[i] = color;
    }
    
    void mark_swap(size_t i, size_t j)
    {
        ASSERT(i < m_array.size());
        ASSERT(j < m_array.size());
        std::swap(m_mark[i], m_mark[j]);
    }
    
    void unmark(size_t i)
    {
        ASSERT(i < m_array.size());
        m_mark[i] = 0;
    }
    
    void unmark_all()
    {
        m_access1 = m_access2 = -1;
        std::fill(m_mark.begin(), m_mark.end(), 0);
        wxMutexLocker lock(m_mutex);
        ASSERT(lock.IsOk());
        m_access_list.clear();
    }
    
    
    void watch(volatile ssize_t* idxptr, unsigned char color = 2)
    {
        wxMutexLocker lock(m_mutex);
        ASSERT(lock.IsOk());
        m_watch.push_back( std::make_pair(idxptr,color) );
    }
    
    void unwatch_all()
    {
        wxMutexLocker lock(m_mutex);
        ASSERT(lock.IsOk());
        m_watch.clear();
    }
};
class SortAlgoThread : public wxThread
{
protected:
    class WMain*        m_wmain;
    class WSortView&    m_array;
    size_t              m_algo;
public:
    SortAlgoThread(class WMain* wmain, class WSortView& array, size_t algo);
    virtual ExitCode Entry();
    void    Exit();
};
#endif