    // Copyright (C) 2003  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #ifndef DLIB_SEQUENCE_SORt_1_
    #define DLIB_SEQUENCE_SORt_1_

    #include "sequence_sort_abstract.h"
    #include "../algs.h"

    namespace dlib
    {

        template <
            typename seq_base
            >
        class sequence_sort_1 : public seq_base
        {
            typedef typename seq_base::type T;

        public:

            /*!
                this is a median of three version of the QuickSort algorithm and
                it sorts sequences of less than 30 elements with a selection sort
            !*/

            void sort (
            );

        private:

            void sort_this_sequence (
                seq_base& sequence
            );
            /*!
                ensures
                    - each element in the sequence is < the element behind it
            !*/

            void selection_sort (
                seq_base& sequence
            );
            /*!
                ensures
                    - sequence is sorted with a selection_sort
            !*/

        };

        template <
            typename seq_base
            >
        inline void swap (
            sequence_sort_1<seq_base>& a,
            sequence_sort_1<seq_base>& b
        ) { a.swap(b); }

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    // member function definitions
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        template <
            typename seq_base
            >
        void sequence_sort_1<seq_base>::
        sort (
        )
        {
            if (this->size() > 1)
            {
                sort_this_sequence(*this);
            }
        }

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    // private member function definitions
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        template <
            typename seq_base
            >
        void sequence_sort_1<seq_base>::
        sort_this_sequence (
            seq_base& sequence
        )
        {
            if (sequence.size() < 30)
            {
                selection_sort(sequence);
            }
            else
            {
                seq_base left, right;
                T partition_element;

                sequence.remove(0,partition_element);

                dlib::median (
                    partition_element,
                    sequence[sequence.size()-1],
                    sequence[(sequence.size()-1)/2]
                );

                // partition sequence into left and right
                T temp;
                while (sequence.size() > 0)
                {
                    sequence.remove(0,temp);
                    if (temp < partition_element)
                    {
                        left.add(0,temp);
                    }
                    else
                    {
                        right.add(0,temp);
                    }
                }

                sort_this_sequence(left);
                sort_this_sequence(right);

                // combine left and right into sequence
                left.swap(sequence);
                sequence.add(sequence.size(),partition_element);
                sequence.cat(right);
            }
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename seq_base
            >
        void sequence_sort_1<seq_base>::
        selection_sort (
            seq_base& sequence
        )
        {
            if (sequence.size() > 2)
            {
                T temp[29];
                unsigned long ssize = sequence.size();

                for (unsigned long i = 0; i < ssize; ++i)
                    sequence.remove(0,temp[i]);

                unsigned long smallest;
                for (unsigned long i = 0; i < ssize - 1; ++i)
                {
                    // find smallest element and swap into i
                    smallest = i;
                    for (unsigned long j = i+1; j < ssize; ++j)
                    {
                        if (temp[j] < temp[smallest])
                            smallest = j;
                    }
                    exchange(temp[smallest],temp[i]);
                }

                for (unsigned long i = 0; i < ssize; ++i)
                    sequence.add(i,temp[i]);
            }
            else if (sequence.size() == 2)
            {
                if (sequence[1] < sequence[0])
                {
                    exchange(sequence[0],sequence[1]);
                }
            }
        }

    // ----------------------------------------------------------------------------------------

    }

    #endif // DLIB_SEQUENCE_SORt_1_