/**
 * This code was placed in the public domain by its author, Niek Sanders, on 
 * June 28, 2004.
 *
 */
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

typedef int DataType;
typedef std::vector< DataType > DataVector;


void prettyPrintVec( std::string title, DataVector& vec ) {

    // Print supplied title
    std::cout << title << ":";

    // Align data on 31st column
    for ( int i = title.size(); i <= 30; i++ ) {
        std::cout << " ";
    }
 
    // Print data items
    DataVector::const_iterator ending = vec.end();
    for ( DataVector::iterator i = vec.begin(); i != ending; ++i ) { 

        std::cout << *i << " "; 

    }

    std::cout << std::endl;
}


int main( int argc, char* argv[] ) {

    // Starting set of numbers
    DataVector numbers;
    numbers.push_back( 3 );
    numbers.push_back( 2 );
    numbers.push_back( 4 );
    numbers.push_back( 1 );
    numbers.push_back( 8 );
    prettyPrintVec( "Original Numbers", numbers );


    // Created a sorted version of numbers
    DataVector sortedNumbers( numbers );
    std::sort( sortedNumbers.begin(), sortedNumbers.end() );
    prettyPrintVec( "Sorted Numbers", sortedNumbers );


    // Add new item and keep things sorted!
    sortedNumbers.push_back( 5 );
    std::inplace_merge( sortedNumbers.begin(), sortedNumbers.end() - 1, 
                        sortedNumbers.end() );
    prettyPrintVec( "Expanded Sorted Numbers", sortedNumbers );


    // Created a reverse ordered version of expanded numbers
    DataVector reversedExpanded( sortedNumbers );
    std::reverse( reversedExpanded.begin(), reversedExpanded.end() );
    prettyPrintVec( "Reversed expanded", reversedExpanded );


    // Reverse the original expanded sequence using a sort with alternative 
    // comparator
    std::sort( sortedNumbers.begin(), sortedNumbers.end(), 
               std::greater< int >() );
    prettyPrintVec( "Reverse sorted original", sortedNumbers );


    // Find objects not divisible by 3
    DataVector divThree;

    std::binder2nd< std::modulus< DataType> > modThree = 
        std::bind2nd( std::modulus< DataType >(), 3 );
    DataVector::iterator i = sortedNumbers.begin();
    while ( i != sortedNumbers.end() ) {

        i = std::find_if( i, sortedNumbers.end(), modThree );

        if ( i != sortedNumbers.end() ) {
            divThree.push_back( *i );
            i++;
        }

    }
    prettyPrintVec( "Numbers not divisible by 3", divThree );


    // Find objects divisible by 3
    divThree.clear();
    i = sortedNumbers.begin();
    while ( i != sortedNumbers.end() ) {

        i = std::find_if( i, sortedNumbers.end(), std::not1( modThree ) );

        if ( i != sortedNumbers.end() ) {
            divThree.push_back( *i );
            i++;
        }

    }
    prettyPrintVec( "Numbers divisible by 3", divThree );
    

}
