<commit_before>
#include <boost/asio.hpp>

#include "vtrc-common/vtrc-mutex-typedefs.h"
#include "vtrc-bind.h"
#include "vtrc-function.h"

#include "vtrc-protocol-layer-s.h"

#include "vtrc-monotonic-timer.h"
#include "vtrc-data-queue.h"
#include "vtrc-hash-iface.h"
#include "vtrc-transformer-iface.h"

#include "vtrc-transport-iface.h"

#include "vtrc-common/vtrc-rpc-service-wrapper.h"
#include "vtrc-common/vtrc-exception.h"
#include "vtrc-common/vtrc-rpc-controller.h"
#include "vtrc-common/vtrc-call-context.h"

#include "vtrc-application.h"

#include "protocol/vtrc-errors.pb.h"
#include "protocol/vtrc-auth.pb.h"
#include "protocol/vtrc-rpc-lowlevel.pb.h"

#include "vtrc-chrono.h"
#include "vtrc-atomic.h"
#include "vtrc-common/vtrc-random-device.h"
#include "vtrc-common/vtrc-delayed-call.h"

namespace vtrc { namespace server {

    namespace gpb   = google::protobuf;
    namespace bsys  = boost::system;
    namespace basio = boost::asio;

    namespace {
        enum init_stage_enum {
             stage_begin             = 1
            ,stage_client_select     = 2
            ,stage_client_ready      = 3
        };

        typedef std::map <
            std::string,
            common::rpc_service_wrapper_sptr
        > service_map;

        typedef vtrc_rpc_lowlevel::lowlevel_unit     lowlevel_unit_type;
        typedef vtrc::shared_ptr<lowlevel_unit_type> lowlevel_unit_sptr;
    }

    namespace data_queue = common::data_queue;

    struct protocol_layer_s::impl {

        typedef impl             this_type;
        typedef protocol_layer_s parent_type;

        application             &app_;
        common::transport_iface *connection_;
        protocol_layer_s        *parent_;
        bool                     ready_;

        service_map              services_;
        shared_mutex             services_lock_;

        std::string              client_id_;

        common::delayed_call     keepalive_calls_;

        typedef vtrc::function<void (void)> stage_function_type;
        stage_function_type  stage_function_;

        vtrc::atomic<unsigned>              current_calls_;
        const unsigned                      maximum_calls_;

        impl( application &a, common::transport_iface *c,
              unsigned maximum_calls)
            :app_(a)
            ,connection_(c)
            ,ready_(false)
            ,current_calls_(0)
            ,maximum_calls_(maximum_calls)
            ,keepalive_calls_(a.get_io_service( ))
        {
            stage_function_ =
                    vtrc::bind( &this_type::on_client_selection, this );

            /// client has only 10 seconds for init connection
            /// todo: think about setting  for this timeout value
            keepalive_calls_.call_from_now(
                        vtrc::bind( &this_type::on_keepavive, this, _1 ),
                        boost::posix_time::seconds( 10 ));
        }

        common::rpc_service_wrapper_sptr get_service( const std::string &name )
        {
            upgradable_lock lk( services_lock_ );
            common::rpc_service_wrapper_sptr result;
            service_map::iterator f( services_.find( name ) );

            if( f != services_.end( ) ) {
                result = f->second;
            } else {
                result = app_.get_service_by_name( connection_, name );
                if( result ) {
                    upgrade_to_unique ulk( lk );
                    services_.insert( std::make_pair( name, result ) );
                }
            }

            return result;
        }

        bool pop_check_init_message(  )
        {

        }

        void pop_message( )
        {
            parent_->pop_message( );
        }

        void on_keepavive( const boost::system::error_code &error )
        {
            if( !error ) {
                /// timeout for client init
                vtrc_auth::init_capsule cap;
                cap.mutable_error( )->set_code( vtrc_errors::ERR_TIMEOUT );
                cap.set_ready( false );
                send_and_close( cap );
            }
        }

        bool check_message_hash( const std::string &mess )
        {
            return parent_->check_message( mess );
        }

        void send_proto_message( const gpb::Message &mess )
        {
            std::string s(mess.SerializeAsString( ));
            connection_->write( s.c_str( ), s.size( ) );
        }

        void send_proto_message( const gpb::Message &mess,
                                 common::closure_type closure, bool on_send)
        {
            std::string s(mess.SerializeAsString( ));
            connection_->write( s.c_str( ), s.size( ), closure, on_send );
        }

        void send_and_close( const gpb::Message &mess )
        {
            send_proto_message( mess, vtrc::bind(
                                    &this_type::close_client, this, _1,
                                     connection_->shared_from_this( )),
                                true );
        }

        void set_client_ready(  )
        {
            keepalive_calls_.cancel( );
            stage_function_ =
                    vtrc::bind( &this_type::on_rcp_call_ready, this );
            parent_->set_ready( true );
        }

        void close_client( const bsys::error_code & /*err*/,
                           common::connection_iface_sptr /*inst*/)
        {
            connection_->close( );
        }

        void on_client_transformer( )
        {

            using namespace common::transformers;
            vtrc_auth::init_capsule capsule;
            bool check = get_pop_message( capsule );

            if( !check ) {
                connection_->close( );
                return;
            }

            if( !capsule.ready( ) ) {
                connection_->close( );
                return;
            }

            vtrc_auth::transformer_setup tsetup;

            tsetup.ParseFromString( capsule.body( ) );

            std::string key(app_.get_session_key( connection_, client_id_ ));

            create_key( key,                // input
                        tsetup.salt1( ),    // input
                        tsetup.salt2( ),    // input
                        key );              // output

            common::transformer_iface *new_transformer =
                                erseefor::create( key.c_str( ), key.size( ) );
            parent_->change_transformer( new_transformer );

            capsule.Clear( );
            capsule.set_ready( true );
            capsule.set_text( "Kiva nahda sinut!" );

            set_client_ready(  );

            send_proto_message( capsule );

        }

        void setup_transformer( unsigned id )
        {
            using namespace common::transformers;

            vtrc_auth::transformer_setup ts;
            vtrc_auth::init_capsule capsule;

            if( id == vtrc_auth::TRANSFORM_NONE ) {

                capsule.set_ready( true );
                capsule.set_text( "Kiva nahda sinut!" );

                set_client_ready(  );

                send_proto_message( capsule );

            } else if( id == vtrc_auth::TRANSFORM_ERSEEFOR ) {

                std::string key(app_.get_session_key(connection_, client_id_));

                generate_key_infos( key,                 // input
                                   *ts.mutable_salt1( ), // output
                                   *ts.mutable_salt2( ), // output
                                    key );               // output

                common::transformer_iface *new_reverter =
                        erseefor::create( key.c_str( ), key.size( ) );

                parent_->change_reverter( new_reverter );

                capsule.set_ready( true );
                capsule.set_body( ts.SerializeAsString( ) );

                stage_function_ =
                        vtrc::bind( &this_type::on_client_transformer, this );

                send_proto_message( capsule );

            } else {
                capsule.set_ready( false );
                vtrc_errors::container *er(capsule.mutable_error( ));
                er->set_code( vtrc_errors::ERR_INVALID_VALUE );
                er->set_category(vtrc_errors::CATEGORY_INTERNAL);
                er->set_additional( "Invalid transformer" );
                send_and_close( capsule );
                return;
            }
        }

        void on_client_selection( )
        {
            vtrc_auth::init_capsule capsule;
            bool check = get_pop_message( capsule );

            if( !check ) {
                connection_->close( );
                return;
            }

            if( !capsule.ready( ) ) {
                connection_->close( );
                return;
            }

            vtrc_auth::client_selection cs;
            cs.ParseFromString( capsule.body( ) );

            common::hash_iface *new_checker(
                        common::hash::create_by_index( cs.hash( ) ) );

            common::hash_iface *new_maker(
                        common::hash::create_by_index( cs.hash( ) ) );

            if( !new_maker ) {
                delete new_checker;
            }

            if( !new_maker || !new_checker ) {
                connection_->close( );
                return;
            }

            client_id_.assign( cs.id( ) );
            parent_->change_hash_checker( new_checker );
            parent_->change_hash_maker( new_maker );

            setup_transformer( cs.transform( ) );

        }

        bool get_pop_message( gpb::Message &capsule )
        {
            std::string &mess(parent_->message_queue( ).front( ));
            bool check = check_message_hash(mess);
            if( !check ) {
                std::cout << "message bad hash "
                          << parent_->message_queue( ).size( )
                          << "...";
                connection_->close( );
                return false;
            }
            parse_message( mess, capsule );
            pop_message( );
            return true;
        }

        void call_done( const boost::system::error_code & /*err*/ )
        {
            --current_calls_;
        }

        void push_call( lowlevel_unit_sptr llu,
                        common::connection_iface_sptr /*conn*/ )
        {
            parent_->make_call( llu,
                vtrc::bind(&this_type::call_done, this, _1 ));
        }

        void send_busy( lowlevel_unit_type &llu )
        {
            if( llu.opt( ).wait( ) ) {
                llu.clear_call( );
                llu.clear_request( );
                llu.clear_response( );
                llu.mutable_error( )->set_code( vtrc_errors::ERR_BUSY );
                parent_->call_rpc_method( llu );
            }
        }

        void process_call( lowlevel_unit_sptr &llu )
        {
            if( ++current_calls_ <= maximum_calls_ ) {
                app_.get_rpc_service( ).post(
                        vtrc::bind( &this_type::push_call, this,
                                    llu, connection_->shared_from_this( )));
            } else {
                --current_calls_;
                send_busy( *llu );
            }
        }

        void push_event_answer( lowlevel_unit_sptr llu,
                                common::connection_iface_sptr /*conn*/ )
        {
            parent_->push_rpc_message( llu->id( ), llu );
        }

        void process_event_cb( lowlevel_unit_sptr &llu )
        {
            parent_->push_rpc_message( llu->id( ), llu );
        }

        void on_rcp_call_ready( )
        {
            typedef vtrc_rpc_lowlevel::message_info message_info;
            while( !parent_->message_queue( ).empty( ) ) {

                lowlevel_unit_sptr llu(vtrc::make_shared<lowlevel_unit_type>());

                if(!get_pop_message( *llu )) {
                    std::cout << "bad hash message!\n";
                    return;
                }

                if( llu->has_info( ) ) {
                    switch (llu->info( ).message_type( )) {
                    case message_info::MESSAGE_CALL:
                        process_call( llu );
                        break;
                    case message_info::MESSAGE_EVENT:
                    case message_info::MESSAGE_CALLBACK:
                    case message_info::MESSAGE_INSERTION_CALL:
                        process_event_cb( llu );
                        break;
                    default:
                        break;
                    }
                }
            }

        }

        void parse_message( const std::string &block, gpb::Message &mess )
        {
            parent_->parse_message( block, mess );
        }

        std::string first_message( )
        {
            vtrc_auth::init_capsule cap;
            vtrc_auth::init_protocol hello_mess;
            cap.set_text( "Tervetuloa!" );
            cap.set_ready( true );

            hello_mess.add_hash_supported( vtrc_auth::HASH_NONE     );
            hello_mess.add_hash_supported( vtrc_auth::HASH_CRC_16   );
            hello_mess.add_hash_supported( vtrc_auth::HASH_CRC_32   );
            hello_mess.add_hash_supported( vtrc_auth::HASH_CRC_64   );
            hello_mess.add_hash_supported( vtrc_auth::HASH_SHA2_256 );

            hello_mess.add_transform_supported( vtrc_auth::TRANSFORM_NONE );
            hello_mess.add_transform_supported( vtrc_auth::TRANSFORM_ERSEEFOR );

            cap.set_body( hello_mess.SerializeAsString( ) );

            return cap.SerializeAsString( );
        }

        void init( )
        {
            static const std::string data(first_message( ));
            connection_->write(data.c_str( ), data.size( ));
        }

        void data_ready( )
        {
            stage_function_( );
        }

    };

    protocol_layer_s::protocol_layer_s( application &a,
                                        common::transport_iface *connection,
                                        unsigned maximym_calls,
                                        size_t mess_len)
        :common::protocol_layer(connection, false, mess_len)
        ,impl_(new impl(a, connection, maximym_calls))
    {
        impl_->parent_ = this;
    }

    protocol_layer_s::~protocol_layer_s( )
    {
        delete impl_;
    }

    void protocol_layer_s::init( )
    {
        impl_->init( );
    }

    void protocol_layer_s::close( )
    {

    }

    void protocol_layer_s::on_data_ready( )
    {
        impl_->data_ready( );
    }

    common::rpc_service_wrapper_sptr protocol_layer_s::get_service_by_name(
                                                        const std::string &name)
    {
        return impl_->get_service(name);
    }

}}

<commit_msg>proto<commit_after>
#include <boost/asio.hpp>

#include "vtrc-common/vtrc-mutex-typedefs.h"
#include "vtrc-bind.h"
#include "vtrc-function.h"

#include "vtrc-protocol-layer-s.h"

#include "vtrc-monotonic-timer.h"
#include "vtrc-data-queue.h"
#include "vtrc-hash-iface.h"
#include "vtrc-transformer-iface.h"

#include "vtrc-transport-iface.h"

#include "vtrc-common/vtrc-rpc-service-wrapper.h"
#include "vtrc-common/vtrc-exception.h"
#include "vtrc-common/vtrc-rpc-controller.h"
#include "vtrc-common/vtrc-call-context.h"

#include "vtrc-application.h"

#include "protocol/vtrc-errors.pb.h"
#include "protocol/vtrc-auth.pb.h"
#include "protocol/vtrc-rpc-lowlevel.pb.h"

#include "vtrc-chrono.h"
#include "vtrc-atomic.h"
#include "vtrc-common/vtrc-random-device.h"
#include "vtrc-common/vtrc-delayed-call.h"

namespace vtrc { namespace server {

    namespace gpb   = google::protobuf;
    namespace bsys  = boost::system;
    namespace basio = boost::asio;

    namespace {
        enum init_stage_enum {
             stage_begin             = 1
            ,stage_client_select     = 2
            ,stage_client_ready      = 3
        };

        typedef std::map <
            std::string,
            common::rpc_service_wrapper_sptr
        > service_map;

        typedef vtrc_rpc_lowlevel::lowlevel_unit     lowlevel_unit_type;
        typedef vtrc::shared_ptr<lowlevel_unit_type> lowlevel_unit_sptr;
    }

    namespace data_queue = common::data_queue;

    struct protocol_layer_s::impl {

        typedef impl             this_type;
        typedef protocol_layer_s parent_type;

        application             &app_;
        common::transport_iface *connection_;
        protocol_layer_s        *parent_;
        bool                     ready_;

        service_map              services_;
        shared_mutex             services_lock_;

        std::string              client_id_;

        common::delayed_call     keepalive_calls_;

        typedef vtrc::function<void (void)> stage_function_type;
        stage_function_type  stage_function_;

        vtrc::atomic<unsigned>              current_calls_;
        const unsigned                      maximum_calls_;

        impl( application &a, common::transport_iface *c,
              unsigned maximum_calls)
            :app_(a)
            ,connection_(c)
            ,ready_(false)
            ,current_calls_(0)
            ,maximum_calls_(maximum_calls)
            ,keepalive_calls_(a.get_io_service( ))
        {
            stage_function_ =
                    vtrc::bind( &this_type::on_client_selection, this );

            /// client has only 10 seconds for init connection
            /// todo: think about setting  for this timeout value
            keepalive_calls_.call_from_now(
                        vtrc::bind( &this_type::on_keepavive, this, _1 ),
                        boost::posix_time::seconds( 10 ));
        }

        common::rpc_service_wrapper_sptr get_service( const std::string &name )
        {
            upgradable_lock lk( services_lock_ );
            common::rpc_service_wrapper_sptr result;
            service_map::iterator f( services_.find( name ) );

            if( f != services_.end( ) ) {
                result = f->second;
            } else {
                result = app_.get_service_by_name( connection_, name );
                if( result ) {
                    upgrade_to_unique ulk( lk );
                    services_.insert( std::make_pair( name, result ) );
                }
            }

            return result;
        }

        bool pop_check_init_message(  )
        {

        }

        void pop_message( )
        {
            parent_->pop_message( );
        }

        void on_keepavive( const boost::system::error_code &error )
        {
            if( !error ) {
                /// timeout for client init
                vtrc_auth::init_capsule cap;
                cap.mutable_error( )->set_code( vtrc_errors::ERR_TIMEOUT );
                cap.set_ready( false );
                send_and_close( cap );
            }
        }

        bool check_message_hash( const std::string &mess )
        {
            return parent_->check_message( mess );
        }

        void send_proto_message( const gpb::Message &mess )
        {
            std::string s(mess.SerializeAsString( ));
            connection_->write( s.c_str( ), s.size( ) );
        }

        void send_proto_message( const gpb::Message &mess,
                                 common::closure_type closure, bool on_send)
        {
            std::string s(mess.SerializeAsString( ));
            connection_->write( s.c_str( ), s.size( ), closure, on_send );
        }

        void send_and_close( const gpb::Message &mess )
        {
            send_proto_message( mess, vtrc::bind(
                                        &this_type::close_client, this, _1,
                                         connection_->shared_from_this( )),
                                true );
        }

        void set_client_ready(  )
        {
            keepalive_calls_.cancel( );
            stage_function_ =
                    vtrc::bind( &this_type::on_rcp_call_ready, this );
            parent_->set_ready( true );
        }

        void close_client( const bsys::error_code & /*err*/,
                           common::connection_iface_sptr /*inst*/)
        {
            connection_->close( );
        }

        void on_client_transformer( )
        {

            using namespace common::transformers;
            vtrc_auth::init_capsule capsule;
            bool check = get_pop_message( capsule );

            if( !check ) {
                connection_->close( );
                return;
            }

            if( !capsule.ready( ) ) {
                connection_->close( );
                return;
            }

            vtrc_auth::transformer_setup tsetup;

            tsetup.ParseFromString( capsule.body( ) );

            std::string key(app_.get_session_key( connection_, client_id_ ));

            create_key( key,                // input
                        tsetup.salt1( ),    // input
                        tsetup.salt2( ),    // input
                        key );              // output

            common::transformer_iface *new_transformer =
                                erseefor::create( key.c_str( ), key.size( ) );
            parent_->change_transformer( new_transformer );

            capsule.Clear( );
            capsule.set_ready( true );
            capsule.set_text( "Kiva nahda sinut!" );

            set_client_ready(  );

            send_proto_message( capsule );

        }

        void setup_transformer( unsigned id )
        {
            using namespace common::transformers;

            vtrc_auth::transformer_setup ts;
            vtrc_auth::init_capsule capsule;

            if( id == vtrc_auth::TRANSFORM_NONE ) {

                capsule.set_ready( true );
                capsule.set_text( "Kiva nahda sinut!" );

                set_client_ready(  );

                send_proto_message( capsule );

            } else if( id == vtrc_auth::TRANSFORM_ERSEEFOR ) {

                std::string key(app_.get_session_key(connection_, client_id_));

                generate_key_infos( key,                 // input
                                   *ts.mutable_salt1( ), // output
                                   *ts.mutable_salt2( ), // output
                                    key );               // output

                common::transformer_iface *new_reverter =
                        erseefor::create( key.c_str( ), key.size( ) );

                parent_->change_reverter( new_reverter );

                capsule.set_ready( true );
                capsule.set_body( ts.SerializeAsString( ) );

                stage_function_ =
                        vtrc::bind( &this_type::on_client_transformer, this );

                send_proto_message( capsule );

            } else {
                capsule.set_ready( false );
                vtrc_errors::container *er(capsule.mutable_error( ));
                er->set_code( vtrc_errors::ERR_INVALID_VALUE );
                er->set_category(vtrc_errors::CATEGORY_INTERNAL);
                er->set_additional( "Invalid transformer" );
                send_and_close( capsule );
                return;
            }
        }

        void on_client_selection( )
        {
            vtrc_auth::init_capsule capsule;
            bool check = get_pop_message( capsule );

            if( !check ) {
                connection_->close( );
                return;
            }

            if( !capsule.ready( ) ) {
                connection_->close( );
                return;
            }

            vtrc_auth::client_selection cs;
            cs.ParseFromString( capsule.body( ) );

            common::hash_iface *new_checker(
                        common::hash::create_by_index( cs.hash( ) ) );

            common::hash_iface *new_maker(
                        common::hash::create_by_index( cs.hash( ) ) );

            if( !new_maker ) {
                delete new_checker;
            }

            if( !new_maker || !new_checker ) {
                connection_->close( );
                return;
            }

            client_id_.assign( cs.id( ) );
            parent_->change_hash_checker( new_checker );
            parent_->change_hash_maker( new_maker );

            setup_transformer( cs.transform( ) );

        }

        bool get_pop_message( gpb::Message &capsule )
        {
            std::string &mess(parent_->message_queue( ).front( ));
            bool check = check_message_hash(mess);
            if( !check ) {
                std::cout << "message bad hash "
                          << parent_->message_queue( ).size( )
                          << "...";
                connection_->close( );
                return false;
            }
            parse_message( mess, capsule );
            pop_message( );
            return true;
        }

        void call_done( const boost::system::error_code & /*err*/ )
        {
            --current_calls_;
        }

        void push_call( lowlevel_unit_sptr llu,
                        common::connection_iface_sptr /*conn*/ )
        {
            parent_->make_call( llu,
                vtrc::bind(&this_type::call_done, this, _1 ));
        }

        void send_busy( lowlevel_unit_type &llu )
        {
            if( llu.opt( ).wait( ) ) {
                llu.clear_call( );
                llu.clear_request( );
                llu.clear_response( );
                llu.mutable_error( )->set_code( vtrc_errors::ERR_BUSY );
                parent_->call_rpc_method( llu );
            }
        }

        void process_call( lowlevel_unit_sptr &llu )
        {
            if( ++current_calls_ <= maximum_calls_ ) {
                app_.get_rpc_service( ).post(
                        vtrc::bind( &this_type::push_call, this,
                                    llu, connection_->shared_from_this( )));
            } else {
                --current_calls_;
                send_busy( *llu );
            }
        }

        void push_event_answer( lowlevel_unit_sptr llu,
                                common::connection_iface_sptr /*conn*/ )
        {
            parent_->push_rpc_message( llu->id( ), llu );
        }

        void process_event_cb( lowlevel_unit_sptr &llu )
        {
            parent_->push_rpc_message( llu->id( ), llu );
        }

        void on_rcp_call_ready( )
        {
            typedef vtrc_rpc_lowlevel::message_info message_info;
            while( !parent_->message_queue( ).empty( ) ) {

                lowlevel_unit_sptr llu(vtrc::make_shared<lowlevel_unit_type>());

                if(!get_pop_message( *llu )) {
                    std::cout << "bad hash message!\n";
                    return;
                }

                if( llu->has_info( ) ) {
                    switch (llu->info( ).message_type( )) {
                    case message_info::MESSAGE_CALL:
                        process_call( llu );
                        break;
                    case message_info::MESSAGE_EVENT:
                    case message_info::MESSAGE_CALLBACK:
                    case message_info::MESSAGE_INSERTION_CALL:
                        process_event_cb( llu );
                        break;
                    default:
                        break;
                    }
                }
            }

        }

        void parse_message( const std::string &block, gpb::Message &mess )
        {
            parent_->parse_message( block, mess );
        }

        std::string first_message( )
        {
            vtrc_auth::init_capsule cap;
            vtrc_auth::init_protocol hello_mess;
            cap.set_text( "Tervetuloa!" );
            cap.set_ready( true );

            hello_mess.add_hash_supported( vtrc_auth::HASH_NONE     );
            hello_mess.add_hash_supported( vtrc_auth::HASH_CRC_16   );
            hello_mess.add_hash_supported( vtrc_auth::HASH_CRC_32   );
            hello_mess.add_hash_supported( vtrc_auth::HASH_CRC_64   );
            hello_mess.add_hash_supported( vtrc_auth::HASH_SHA2_256 );

            hello_mess.add_transform_supported( vtrc_auth::TRANSFORM_NONE );
            hello_mess.add_transform_supported( vtrc_auth::TRANSFORM_ERSEEFOR );

            cap.set_body( hello_mess.SerializeAsString( ) );

            return cap.SerializeAsString( );
        }

        void init( )
        {
            static const std::string data(first_message( ));
            connection_->write(data.c_str( ), data.size( ));
        }

        void data_ready( )
        {
            stage_function_( );
        }

    };

    protocol_layer_s::protocol_layer_s( application &a,
                                        common::transport_iface *connection,
                                        unsigned maximym_calls,
                                        size_t mess_len)
        :common::protocol_layer(connection, false, mess_len)
        ,impl_(new impl(a, connection, maximym_calls))
    {
        impl_->parent_ = this;
    }

    protocol_layer_s::~protocol_layer_s( )
    {
        delete impl_;
    }

    void protocol_layer_s::init( )
    {
        impl_->init( );
    }

    void protocol_layer_s::close( )
    {

    }

    void protocol_layer_s::on_data_ready( )
    {
        impl_->data_ready( );
    }

    common::rpc_service_wrapper_sptr protocol_layer_s::get_service_by_name(
                                                        const std::string &name)
    {
        return impl_->get_service(name);
    }

}}

<|endoftext|>


<commit_before>#include "media_config_loader.h"
#include "log.h"

using ::com::kurento::log::Log;

static Log l("media_config_loader");
#define d(...) aux_debug(l, __VA_ARGS__);
#define i(...) aux_info(l, __VA_ARGS__);
#define e(...) aux_error(l, __VA_ARGS__);
#define w(...) aux_warn(l, __VA_ARGS__);

#define DEFAULT_ID "12345"

#define MEDIAS_KEY "medias"

#define MEDIA_GROUP "Media"
#define CODECS_KEY "codecs"
#define TRANSPORT_KEY "transport"

#define TRANSPORT_GROUP "Transport"

#define CODEC_GROUP "Codec"
#define ID_KEY "id"
#define NAME_KEY "name"
#define CLOCKRATE_KEY "clockRate"
#define CHANNELS "channels"
#define WIDTH "width"
#define HEIGHT "height"
#define BITRATE "bitrate"

#define EXTRA_PARAMS "extra"

using ::com::kurento::commons::mediaspec::MediaSpec;
using ::com::kurento::commons::mediaspec::Transport;
using ::com::kurento::commons::mediaspec::Payload;

static void
load_codec(Glib::KeyFile &configFile, const std::string &codecgrp, Payload &pay) {
	// TODO: Implement this function
	d("Loading config for: " + codecgrp);
	throw Glib::KeyFileError(Glib::KeyFileError::NOT_FOUND, "Not implemented");
}

static void
load_transport(Glib::KeyFile &configFile, const std::string &transportgrp,
								Transport &tr) {
	// TODO: Implement this function
	d("Loading config for: " + transportgrp);
	throw Glib::KeyFileError(Glib::KeyFileError::NOT_FOUND, "Not implemented");
}

static void
load_media(Glib::KeyFile &configFile, const std::string &mediagrp,
							MediaSpec &media)
{
	d("Loading config for media: " + mediagrp);
	if (!configFile.has_group(mediagrp)) {
		e("No codecs set, you won't be able to communicate with others");
		return;
	}

	Glib::ArrayHandle<Glib::ustring> codecs =
				configFile.get_string_list(mediagrp, CODECS_KEY);

	Glib::ArrayHandle<Glib::ustring>::const_iterator it = codecs.begin();
	for (; it != codecs.end(); it ++) {
		Payload pay;
		try {
			load_codec(configFile, CODEC_GROUP " " + *it, pay);
			media.payloads.push_back(pay);
		} catch (Glib::KeyFileError err) {
			w(err.what());
			w("error loading codec configuration: " + *it);
		}
	}

	std::string transport = configFile.get_string(mediagrp, TRANSPORT_KEY);
	load_transport(configFile, TRANSPORT_GROUP " " + transport,
							media.transport);
}

void
load_spec(Glib::KeyFile &configFile, SessionSpec &spec) {
	Glib::ArrayHandle<Glib::ustring> medias =
			configFile.get_string_list(SERVER_GROUP, MEDIAS_KEY);

	Glib::ArrayHandle<Glib::ustring>::const_iterator it = medias.begin();
	for (; it != medias.end(); it ++) {
		MediaSpec media;
		try {
			load_media(configFile, MEDIA_GROUP " " + *it, media);
			spec.medias.push_back(media);
		} catch (Glib::KeyFileError err) {
			w(err.what());
			w("Error loading media configuration: " + *it);
		}
	}

	spec.__set_id(DEFAULT_ID);
}
<commit_msg>Add configuration loader for transport<commit_after>#include "media_config_loader.h"
#include "log.h"

using ::com::kurento::log::Log;

static Log l("media_config_loader");
#define d(...) aux_debug(l, __VA_ARGS__);
#define i(...) aux_info(l, __VA_ARGS__);
#define e(...) aux_error(l, __VA_ARGS__);
#define w(...) aux_warn(l, __VA_ARGS__);

#define DEFAULT_ID "12345"

#define MEDIAS_KEY "medias"

#define MEDIA_GROUP "Media"
#define CODECS_KEY "codecs"
#define TRANSPORT_KEY "transport"

#define TRANSPORT_GROUP "Transport"
#define ADDRESS_KEY "address"

#define CODEC_GROUP "Codec"
#define ID_KEY "id"
#define NAME_KEY "name"
#define CLOCKRATE_KEY "clockRate"
#define CHANNELS "channels"
#define WIDTH "width"
#define HEIGHT "height"
#define BITRATE "bitrate"

#define EXTRA_PARAMS "extra"

using ::com::kurento::commons::mediaspec::MediaSpec;
using ::com::kurento::commons::mediaspec::Transport;
using ::com::kurento::commons::mediaspec::Payload;

static void
load_codec(Glib::KeyFile &configFile, const std::string &codecgrp, Payload &pay) {
	// TODO: Implement this function
	d("Loading config for: " + codecgrp);
	throw Glib::KeyFileError(Glib::KeyFileError::NOT_FOUND, "Not implemented");
}

static void
load_transport(Glib::KeyFile &configFile, const std::string &transportgrp,
								Transport &tr) {
	d("Loading config for: " + transportgrp);

	tr.rtp.__set_address(configFile.get_string(transportgrp, ADDRESS_KEY));
	tr.__isset.rtp = true;
}

static void
load_media(Glib::KeyFile &configFile, const std::string &mediagrp,
							MediaSpec &media)
{
	d("Loading config for media: " + mediagrp);
	if (!configFile.has_group(mediagrp)) {
		e("No codecs set, you won't be able to communicate with others");
		return;
	}

	Glib::ArrayHandle<Glib::ustring> codecs =
				configFile.get_string_list(mediagrp, CODECS_KEY);

	Glib::ArrayHandle<Glib::ustring>::const_iterator it = codecs.begin();
	for (; it != codecs.end(); it ++) {
		Payload pay;
		try {
			load_codec(configFile, CODEC_GROUP " " + *it, pay);
			media.payloads.push_back(pay);
		} catch (Glib::KeyFileError err) {
			w(err.what());
			w("error loading codec configuration: " + *it);
		}
	}

	std::string transport = configFile.get_string(mediagrp, TRANSPORT_KEY);
	load_transport(configFile, TRANSPORT_GROUP " " + transport,
							media.transport);
}

void
load_spec(Glib::KeyFile &configFile, SessionSpec &spec) {
	Glib::ArrayHandle<Glib::ustring> medias =
			configFile.get_string_list(SERVER_GROUP, MEDIAS_KEY);

	Glib::ArrayHandle<Glib::ustring>::const_iterator it = medias.begin();
	for (; it != medias.end(); it ++) {
		MediaSpec media;
		try {
			load_media(configFile, MEDIA_GROUP " " + *it, media);
			spec.medias.push_back(media);
		} catch (Glib::KeyFileError err) {
			w(err.what());
			w("Error loading media configuration: " + *it);
		}
	}

	spec.__set_id(DEFAULT_ID);
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "internal/file.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#include <algorithm>
#include <cassert>
#include <cerrno>
#include <cstdlib>
#include <ios>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <utility>

#include "absl/strings/string_view.h"

#include "internal/random.h"

namespace phst_rules_elisp {

file::file() { this->setp(put_.data(), put_.data() + put_.size()); }

file::file(std::string path, const file_mode mode) : file() {
  this->open(std::move(path), mode);
}

file::~file() noexcept {
  if (fd_ >= 0) std::clog << "file " << path_ << " still open" << std::endl;
}

void file::open(std::string path, const file_mode mode) {
  int fd = -1;
  while (true) {
    fd = ::open(path.c_str(), static_cast<int>(mode) | O_CLOEXEC,
                S_IRUSR | S_IWUSR);
    if (fd >= 0 || errno != EINTR) break;
  }
  if (fd < 0) {
    throw std::system_error(errno, std::system_category(),
                            "open(" + path + ')');
  }
  fd_ = fd;
  path_ = std::move(path);
}

std::FILE* file::open_c_file(const char* const mode) {
  const auto file = fdopen(fd_, mode);
  if (file == nullptr) {
    throw std::system_error(errno, std::system_category(), "fdopen");
  }
  return file;
}

void file::close() {
  if (fd_ < 0) return;
  if (!this->flush()) {
    throw std::ios::failure("error closing file " + path_);
  }
  int status = -1;
  while (true) {
    status = ::close(fd_);
    if (status == 0 || errno != EINTR) break;
  }
  if (status != 0) {
    throw std::system_error(errno, std::system_category(), "close");
  }
  fd_ = -1;
  this->do_close();
  path_.clear();
}

void file::do_close() {}

file::int_type file::overflow(const int_type ch) {
  assert(this->pptr() == this->epptr());
  if (!this->flush()) return traits_type::eof();
  if (traits_type::eq_int_type(ch, traits_type::eof())) {
    return traits_type::not_eof(0);
  }
  assert(this->pptr() == put_.data());
  assert(this->epptr() > put_.data());
  traits_type::assign(put_.front(), traits_type::to_char_type(ch));
  this->pbump(1);
  return ch;
}

std::streamsize file::xsputn(const char_type* const data,
                             const std::streamsize count) {
  if (!this->flush()) return 0;
  return this->write(data, count);
}

std::size_t file::write(const char* data, std::size_t count) {
  std::size_t written = 0;
  while (count > 0) {
    const auto n = ::write(fd_, data, count);
    if (n < 0) throw std::system_error(errno, std::system_category(), "write");
    if (n == 0) break;
    written += n;
    data += n;
    count -= n;
  }
  return written;
}

file::int_type file::underflow() {
  assert(this->gptr() == this->egptr());
  const auto read = this->read(get_.data(), get_.size());
  this->setg(get_.data(), get_.data(), get_.data() + read);
  if (read == 0) return traits_type::eof();
  assert(this->gptr() != nullptr);
  assert(this->gptr() != this->egptr());
  return traits_type::to_int_type(*this->gptr());
}

std::streamsize file::xsgetn(char_type* data, std::streamsize count) {
  if (count == 0) return 0;
  std::streamsize read = 0;
  if (this->gptr() != nullptr && this->egptr() != this->gptr()) {
    read = std::min(count, this->egptr() - this->gptr());
    traits_type::copy(data, this->gptr(), read);
    data += read;
    count -= read;
    this->setg(this->gptr(), this->gptr() + read, this->egptr());
  }
  return read + this->read(data, count);
}

std::size_t file::read(char* data, std::size_t count) {
  std::size_t read = 0;
  while (count > 0) {
    const auto n = ::read(fd_, data, count);
    if (n < 0) throw std::system_error(errno, std::system_category(), "read");
    if (n == 0) break;
    read += n;
    data += n;
    count -= n;
  }
  return read;
}

int file::sync() {
  if (!this->flush()) return -1;
  if (::fsync(fd_) < 0) {
    throw std::system_error(errno, std::system_category(), "fsync");
  }
  return 0;
}

[[nodiscard]] bool file::flush() {
  assert(this->pbase() != nullptr);
  assert(this->pptr() != nullptr);
  const auto signed_count = this->pptr() - this->pbase();
  assert(signed_count >= 0);
  const auto count = static_cast<std::size_t>(signed_count);
  const auto written = this->write(this->pbase(), count);
  assert(written <= count);
  if (written < count) return false;
  this->setp(put_.data(), put_.data() + put_.size());
  return true;
}

temp_file::temp_file(const std::string& directory, const absl::string_view tmpl,
                     random& random) {
  for (int i = 0; i < 10; i++) {
    auto name = join_path(directory, random.temp_name(tmpl));
    if (!file_exists(name)) {
      this->open(std::move(name),
                 file_mode::readwrite | file_mode::create | file_mode::excl);
      return;
    }
  }
  throw std::runtime_error("can’t create temporary file in directory " +
                           directory + " with template " + std::string(tmpl));
}

temp_file::~temp_file() noexcept {
  const auto& path = this->path();
  const auto code = this->remove();
  // Only print an error if removing the file failed (“false” return value), but
  // the file wasn’t already removed before (zero error code).
  if (code && code != std::errc::no_such_file_or_directory) {
    std::clog << "error removing temporary file " << path << ": " << code
              << ": " << code.message() << std::endl;
  }
}

void temp_file::do_close() {
  const auto code = this->remove();
  if (code) throw std::system_error(code);
}

[[nodiscard]] std::error_code temp_file::remove() noexcept {
  return remove_file(this->path());
}

static constexpr absl::string_view remove_prefix(const absl::string_view string,
                                                 const char prefix) noexcept {
  return (string.empty() || string.front() != prefix) ? string
                                                      : string.substr(1);
}

static constexpr absl::string_view remove_suffix(const absl::string_view string,
                                                 const char suffix) noexcept {
  return (string.empty() || string.back() != suffix)
             ? string
             : string.substr(0, string.size() - 1);
}

std::string join_path(const absl::string_view a, const absl::string_view b) {
  return std::string(remove_slash(a)) + '/' +
         std::string(remove_prefix(b, '/'));
}

std::string make_absolute(const absl::string_view name) {
  if (is_absolute(name)) return std::string(name);
  struct free {
    void operator()(void* const ptr) const noexcept { std::free(ptr); }
  };
  const std::unique_ptr<char, free> dir(get_current_dir_name());
  if (dir == nullptr) {
    throw std::system_error(errno, std::system_category(),
                            "get_current_dir_name");
  }
  return join_path(dir.get(), name);
}

[[nodiscard]] bool file_exists(const std::string& name) noexcept {
  struct stat info;
  return ::lstat(name.c_str(), &info) == 0;
}

[[nodiscard]] std::error_code remove_file(const std::string& name) noexcept {
  return std::error_code(::unlink(name.c_str()) == 0 ? 0 : errno,
                         std::system_category());
}

[[nodiscard]] std::string temp_dir() {
  const std::array<const char*, 2> vars = {"TEST_TMPDIR", "TMPDIR"};
  for (const auto var : vars) {
    const auto value = std::getenv(var);
    if (value != nullptr && *value != '\0') return value;
  }
  return "/tmp";
}

directory::directory(const std::string& name) : dir_(::opendir(name.c_str())) {
  if (dir_ == nullptr) {
    throw std::system_error(errno, std::system_category(),
                            "opendir(" + name + ')');
  }
}

directory::~directory() noexcept {
  const auto code = this->close();
  if (code) std::clog << code << ": " << code.message() << std::endl;
}

[[nodiscard]] std::error_code directory::close() noexcept {
  if (dir_ == nullptr) return std::error_code();
  const std::error_code code(::closedir(dir_) == 0 ? 0 : errno,
                             std::system_category());
  dir_ = nullptr;
  return code;
}

void directory::iterator::advance() {
  errno = 0;
  const auto entry = ::readdir(dir_);
  if (entry == nullptr) {
    dir_ = nullptr;
    if (errno != 0) {
      throw std::system_error(errno, std::system_category(), "readdir");
    }
    entry_.clear();
  } else {
    entry_ = entry->d_name;
  }
}

}  // phst_rules_elisp
<commit_msg>Always call fsync, even if flushing the buffer failed.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "internal/file.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#include <algorithm>
#include <cassert>
#include <cerrno>
#include <cstdlib>
#include <ios>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <utility>

#include "absl/strings/string_view.h"

#include "internal/random.h"

namespace phst_rules_elisp {

file::file() { this->setp(put_.data(), put_.data() + put_.size()); }

file::file(std::string path, const file_mode mode) : file() {
  this->open(std::move(path), mode);
}

file::~file() noexcept {
  if (fd_ >= 0) std::clog << "file " << path_ << " still open" << std::endl;
}

void file::open(std::string path, const file_mode mode) {
  int fd = -1;
  while (true) {
    fd = ::open(path.c_str(), static_cast<int>(mode) | O_CLOEXEC,
                S_IRUSR | S_IWUSR);
    if (fd >= 0 || errno != EINTR) break;
  }
  if (fd < 0) {
    throw std::system_error(errno, std::system_category(),
                            "open(" + path + ')');
  }
  fd_ = fd;
  path_ = std::move(path);
}

std::FILE* file::open_c_file(const char* const mode) {
  const auto file = fdopen(fd_, mode);
  if (file == nullptr) {
    throw std::system_error(errno, std::system_category(), "fdopen");
  }
  return file;
}

void file::close() {
  if (fd_ < 0) return;
  if (!this->flush()) {
    throw std::ios::failure("error closing file " + path_);
  }
  int status = -1;
  while (true) {
    status = ::close(fd_);
    if (status == 0 || errno != EINTR) break;
  }
  if (status != 0) {
    throw std::system_error(errno, std::system_category(), "close");
  }
  fd_ = -1;
  this->do_close();
  path_.clear();
}

void file::do_close() {}

file::int_type file::overflow(const int_type ch) {
  assert(this->pptr() == this->epptr());
  if (!this->flush()) return traits_type::eof();
  if (traits_type::eq_int_type(ch, traits_type::eof())) {
    return traits_type::not_eof(0);
  }
  assert(this->pptr() == put_.data());
  assert(this->epptr() > put_.data());
  traits_type::assign(put_.front(), traits_type::to_char_type(ch));
  this->pbump(1);
  return ch;
}

std::streamsize file::xsputn(const char_type* const data,
                             const std::streamsize count) {
  if (!this->flush()) return 0;
  return this->write(data, count);
}

std::size_t file::write(const char* data, std::size_t count) {
  std::size_t written = 0;
  while (count > 0) {
    const auto n = ::write(fd_, data, count);
    if (n < 0) throw std::system_error(errno, std::system_category(), "write");
    if (n == 0) break;
    written += n;
    data += n;
    count -= n;
  }
  return written;
}

file::int_type file::underflow() {
  assert(this->gptr() == this->egptr());
  const auto read = this->read(get_.data(), get_.size());
  this->setg(get_.data(), get_.data(), get_.data() + read);
  if (read == 0) return traits_type::eof();
  assert(this->gptr() != nullptr);
  assert(this->gptr() != this->egptr());
  return traits_type::to_int_type(*this->gptr());
}

std::streamsize file::xsgetn(char_type* data, std::streamsize count) {
  if (count == 0) return 0;
  std::streamsize read = 0;
  if (this->gptr() != nullptr && this->egptr() != this->gptr()) {
    read = std::min(count, this->egptr() - this->gptr());
    traits_type::copy(data, this->gptr(), read);
    data += read;
    count -= read;
    this->setg(this->gptr(), this->gptr() + read, this->egptr());
  }
  return read + this->read(data, count);
}

std::size_t file::read(char* data, std::size_t count) {
  std::size_t read = 0;
  while (count > 0) {
    const auto n = ::read(fd_, data, count);
    if (n < 0) throw std::system_error(errno, std::system_category(), "read");
    if (n == 0) break;
    read += n;
    data += n;
    count -= n;
  }
  return read;
}

int file::sync() {
  const auto success = this->flush();
  if (::fsync(fd_) < 0) {
    throw std::system_error(errno, std::system_category(), "fsync");
  }
  return success ? 0 : -1;
}

[[nodiscard]] bool file::flush() {
  assert(this->pbase() != nullptr);
  assert(this->pptr() != nullptr);
  const auto signed_count = this->pptr() - this->pbase();
  assert(signed_count >= 0);
  const auto count = static_cast<std::size_t>(signed_count);
  const auto written = this->write(this->pbase(), count);
  assert(written <= count);
  if (written < count) return false;
  this->setp(put_.data(), put_.data() + put_.size());
  return true;
}

temp_file::temp_file(const std::string& directory, const absl::string_view tmpl,
                     random& random) {
  for (int i = 0; i < 10; i++) {
    auto name = join_path(directory, random.temp_name(tmpl));
    if (!file_exists(name)) {
      this->open(std::move(name),
                 file_mode::readwrite | file_mode::create | file_mode::excl);
      return;
    }
  }
  throw std::runtime_error("can’t create temporary file in directory " +
                           directory + " with template " + std::string(tmpl));
}

temp_file::~temp_file() noexcept {
  const auto& path = this->path();
  const auto code = this->remove();
  // Only print an error if removing the file failed (“false” return value), but
  // the file wasn’t already removed before (zero error code).
  if (code && code != std::errc::no_such_file_or_directory) {
    std::clog << "error removing temporary file " << path << ": " << code
              << ": " << code.message() << std::endl;
  }
}

void temp_file::do_close() {
  const auto code = this->remove();
  if (code) throw std::system_error(code);
}

[[nodiscard]] std::error_code temp_file::remove() noexcept {
  return remove_file(this->path());
}

static constexpr absl::string_view remove_prefix(const absl::string_view string,
                                                 const char prefix) noexcept {
  return (string.empty() || string.front() != prefix) ? string
                                                      : string.substr(1);
}

static constexpr absl::string_view remove_suffix(const absl::string_view string,
                                                 const char suffix) noexcept {
  return (string.empty() || string.back() != suffix)
             ? string
             : string.substr(0, string.size() - 1);
}

std::string join_path(const absl::string_view a, const absl::string_view b) {
  return std::string(remove_slash(a)) + '/' +
         std::string(remove_prefix(b, '/'));
}

std::string make_absolute(const absl::string_view name) {
  if (is_absolute(name)) return std::string(name);
  struct free {
    void operator()(void* const ptr) const noexcept { std::free(ptr); }
  };
  const std::unique_ptr<char, free> dir(get_current_dir_name());
  if (dir == nullptr) {
    throw std::system_error(errno, std::system_category(),
                            "get_current_dir_name");
  }
  return join_path(dir.get(), name);
}

[[nodiscard]] bool file_exists(const std::string& name) noexcept {
  struct stat info;
  return ::lstat(name.c_str(), &info) == 0;
}

[[nodiscard]] std::error_code remove_file(const std::string& name) noexcept {
  return std::error_code(::unlink(name.c_str()) == 0 ? 0 : errno,
                         std::system_category());
}

[[nodiscard]] std::string temp_dir() {
  const std::array<const char*, 2> vars = {"TEST_TMPDIR", "TMPDIR"};
  for (const auto var : vars) {
    const auto value = std::getenv(var);
    if (value != nullptr && *value != '\0') return value;
  }
  return "/tmp";
}

directory::directory(const std::string& name) : dir_(::opendir(name.c_str())) {
  if (dir_ == nullptr) {
    throw std::system_error(errno, std::system_category(),
                            "opendir(" + name + ')');
  }
}

directory::~directory() noexcept {
  const auto code = this->close();
  if (code) std::clog << code << ": " << code.message() << std::endl;
}

[[nodiscard]] std::error_code directory::close() noexcept {
  if (dir_ == nullptr) return std::error_code();
  const std::error_code code(::closedir(dir_) == 0 ? 0 : errno,
                             std::system_category());
  dir_ = nullptr;
  return code;
}

void directory::iterator::advance() {
  errno = 0;
  const auto entry = ::readdir(dir_);
  if (entry == nullptr) {
    dir_ = nullptr;
    if (errno != 0) {
      throw std::system_error(errno, std::system_category(), "readdir");
    }
    entry_.clear();
  } else {
    entry_ = entry->d_name;
  }
}

}  // phst_rules_elisp
<|endoftext|>


<commit_before>#include "propertyeditordelegate.h"
#include "propertyeditorproxymodel.h"
#include <QtCore/QDebug>
#include <QtGui/QComboBox>
#include <QtGui/QPushButton>
#include <QtGui/QPushButton>

#include "mainwindow.h"
#include "openShapeEditorButton.h"

#include "referencetypewindow.h"
#include "buttonRefWindow.h"

using namespace qReal;

PropertyEditorDelegate::PropertyEditorDelegate(QObject *parent)
		: QItemDelegate(parent)
		, mMainWindow(NULL)
		, mLogicalModelAssistApi(NULL)
{
}

QWidget *PropertyEditorDelegate::createEditor(QWidget *parent,
		const QStyleOptionViewItem &/*option*/,
		const QModelIndex &index) const
{
	PropertyEditorModel *model = const_cast<PropertyEditorModel*>(dynamic_cast<const PropertyEditorModel*>(index.model()));
	QString propertyName = model->data(index.sibling(index.row(), 0), Qt::DisplayRole).toString();
	if (propertyName == "shape") {
		QString propertyValue = model->data(index.sibling(index.row(), index.column()), Qt::DisplayRole).toString();
		QPersistentModelIndex const actualIndex = model->modelIndex(index.row());
		int role = model->roleByIndex(index.row());
		OpenShapeEditorButton *button = new OpenShapeEditorButton(parent, actualIndex, role, propertyValue);
		button->setText("Open Shape Editor");
		QObject::connect(button, SIGNAL(clicked()), mMainWindow, SLOT(openShapeEditor()));
		return button;
	}

	QStringList const values = model->enumValues(index);
	if (!values.isEmpty()) {
		QComboBox * const editor = new QComboBox(parent);
		foreach (QString item, values)
			editor->addItem(item);
		return editor;
	}

	QString typeName = model->typeName(index);
	if (typeName != "int" && typeName != "string" && typeName != "") {
		int const role = model->roleByIndex(index.row());
		QModelIndex const &actualIndex = model->modelIndex(index.row());
		ButtonRefWindow * const button = new ButtonRefWindow(parent, typeName
				, *mLogicalModelAssistApi, role, actualIndex, mMainWindow);
		return button;
	}
	QLineEdit *editor = new QLineEdit(parent);

	return editor;
}

void PropertyEditorDelegate::setEditorData(QWidget *editor,
		const QModelIndex &index) const
{
	QString value = index.model()->data(index, Qt::DisplayRole).toString();

	QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(editor);
	if (lineEdit)
		lineEdit->setText(value);
	else {
		QComboBox *comboEdit = dynamic_cast<QComboBox*>(editor);
		if (comboEdit)
			comboEdit->setCurrentIndex(comboEdit->findText(value));
	}
}

void PropertyEditorDelegate::setModelData(QWidget *editor
		, QAbstractItemModel *model
		, const QModelIndex &index) const
{
	QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(editor);
	QComboBox *comboEdit = dynamic_cast<QComboBox*>(editor);

	QString value;
	if (lineEdit)
		value = lineEdit->text();
	else if (comboEdit)
		value = comboEdit->currentText();
	else
		return;

	model->setData(index, value, Qt::EditRole);
	mMainWindow->propertyEditorScrollTo(index);
}

void PropertyEditorDelegate::updateEditorGeometry(QWidget *editor,
		const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const
{
	editor->setGeometry(option.rect);
}

void PropertyEditorDelegate::init(MainWindow *mainWindow
		, qReal::models::LogicalModelAssistApi * const logicalModelAssistApi)
{
	mMainWindow = mainWindow;
	mLogicalModelAssistApi = logicalModelAssistApi;
}
<commit_msg>Fixed #389, once again<commit_after>#include "propertyeditordelegate.h"
#include "propertyeditorproxymodel.h"
#include <QtCore/QDebug>
#include <QtGui/QComboBox>
#include <QtGui/QPushButton>
#include <QtGui/QPushButton>

#include "mainwindow.h"
#include "openShapeEditorButton.h"

#include "referencetypewindow.h"
#include "buttonRefWindow.h"

using namespace qReal;

PropertyEditorDelegate::PropertyEditorDelegate(QObject *parent)
		: QItemDelegate(parent)
		, mMainWindow(NULL)
		, mLogicalModelAssistApi(NULL)
{
}

QWidget *PropertyEditorDelegate::createEditor(QWidget *parent,
		const QStyleOptionViewItem &option,
		const QModelIndex &index) const
{
	Q_UNUSED(option);

	PropertyEditorModel *model = const_cast<PropertyEditorModel*>(dynamic_cast<const PropertyEditorModel*>(index.model()));
	QString propertyName = model->data(index.sibling(index.row(), 0), Qt::DisplayRole).toString();
	if (propertyName == "shape") {
		QString propertyValue = model->data(index.sibling(index.row(), index.column()), Qt::DisplayRole).toString();
		QPersistentModelIndex const actualIndex = model->modelIndex(index.row());
		int role = model->roleByIndex(index.row());
		OpenShapeEditorButton *button = new OpenShapeEditorButton(parent, actualIndex, role, propertyValue);
		button->setText("Open Shape Editor");
		QObject::connect(button, SIGNAL(clicked()), mMainWindow, SLOT(openShapeEditor()));
		return button;
	}

	QStringList const values = model->enumValues(index);
	if (!values.isEmpty()) {
		QComboBox * const editor = new QComboBox(parent);
		foreach (QString item, values)
			editor->addItem(item);
		return editor;
	}

	QString typeName = model->typeName(index).toLower();
	if (typeName != "int" && typeName != "string" && !typeName.isEmpty()) {
		int const role = model->roleByIndex(index.row());
		QModelIndex const &actualIndex = model->modelIndex(index.row());
		ButtonRefWindow * const button = new ButtonRefWindow(parent, typeName
				, *mLogicalModelAssistApi, role, actualIndex, mMainWindow);
		return button;
	}
	QLineEdit * const editor = new QLineEdit(parent);

	return editor;
}

void PropertyEditorDelegate::setEditorData(QWidget *editor,
		const QModelIndex &index) const
{
	QString value = index.model()->data(index, Qt::DisplayRole).toString();

	QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(editor);
	if (lineEdit)
		lineEdit->setText(value);
	else {
		QComboBox *comboEdit = dynamic_cast<QComboBox*>(editor);
		if (comboEdit)
			comboEdit->setCurrentIndex(comboEdit->findText(value));
	}
}

void PropertyEditorDelegate::setModelData(QWidget *editor
		, QAbstractItemModel *model
		, const QModelIndex &index) const
{
	QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(editor);
	QComboBox *comboEdit = dynamic_cast<QComboBox*>(editor);

	QString value;
	if (lineEdit)
		value = lineEdit->text();
	else if (comboEdit)
		value = comboEdit->currentText();
	else
		return;

	model->setData(index, value, Qt::EditRole);
	mMainWindow->propertyEditorScrollTo(index);
}

void PropertyEditorDelegate::updateEditorGeometry(QWidget *editor,
		const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const
{
	editor->setGeometry(option.rect);
}

void PropertyEditorDelegate::init(MainWindow *mainWindow
		, qReal::models::LogicalModelAssistApi * const logicalModelAssistApi)
{
	mMainWindow = mainWindow;
	mLogicalModelAssistApi = logicalModelAssistApi;
}
<|endoftext|>


<commit_before>#include <tamer/fdhmsg.hh>
#include <signal.h>

void terminate(int);
int query_count = 0;

int main (void) {
  char buf[8192];
  int len;
  int fd;

  pid_t pid;
  int socks[2], chfd;

  fdh_msg * msg;

  char * fname;
  struct stat * stat;

  size_t size;
  ssize_t ssize;

  if (signal(SIGTERM, terminate) == SIG_ERR) {
    perror("unable to set signal");
    exit(0);
  }

  for (;;) {
    if ((len = fdh_recv(0, &fd, buf, sizeof(buf))) < 0) {
      perror("recvmsg");
      goto exit_;
    } else if (len == 0)
      goto exit_;

    query_count ++;
    msg = (fdh_msg *)buf;

    switch (msg->query.req) {
      case FDH_CLONE:
        printf("clone %d\n", getpid());
        if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0) {
          chfd = -1;
          msg->reply.err = errno;
          goto forkerr;
        }

        msg->reply.pid = pid = fork();
        if (pid < 0) {
          chfd = -1;
          msg->reply.err = errno;
          goto forkerr;
        } else if (pid == 0) {
          // child
          //printf("!child %d\n", getpid());
          close(0);
          close(socks[0]);
          if (dup2(socks[1], 0) < 0) {
            close(socks[1]);
            goto exit_;
          }
          close(socks[1]);
          break;
        }

        chfd = socks[0];
        msg->reply.err = 0;
      forkerr:
        close(socks[1]);
        if (fdh_send(0, chfd, (char *)msg, FDH_MSG_SIZE) < 0) {
          perror("sendmsg");
          close(socks[0]);
          goto exit_;
        }
        close(socks[0]);
        break;
      /*case FDH_KILL:
        printf("kill %d\n", getpid());
        goto exit_;
        break;*/
      case FDH_OPEN:
        //printf("open %d\n", getpid());
        fname = (char *)&buf[FDH_MSG_SIZE];
        msg->reply.err = ((fd =
              open(fname, msg->query.flags, msg->query.mode)) < 0) ? errno : 0;
        if (fdh_send(0, fd, (char *)msg, FDH_MSG_SIZE) < 0) {
          perror("sendmsg");
          goto exit;
        }
        close(fd);
        break;
      case FDH_STAT:
        //printf("stat %d\n", getpid());
        stat = (struct stat *)&buf[FDH_MSG_SIZE];
        msg->reply.err = (fstat(fd, stat) < 0) ? errno : 0;
        if (fdh_send(0, fd, buf, sizeof(int) + sizeof(struct stat)) < 0) {
          perror("sendmsg");
          goto exit;
        }
        close(fd);
        break;
      case FDH_READ:
        //printf("read %d\n", getpid());
        if (sendfile(0, fd, NULL, msg->query.size) < 0) {
          /* TODO handle error gracefully ?*/
          perror("sendfile");
          goto exit;
        }
        close(fd);
        break;
      case FDH_WRITE:
        //printf("write %d %d\n", fd, getpid());
        size = msg->query.size;
        do {
          if ((ssize = read(0, buf, sizeof(buf))) < 0) {
            /* TODO handle error gracefully ? signal to parent?*/
            perror("helper: read");
            goto exit;
          } else if (ssize == 0)
            break;
          if (ssize)
            if (ssize != write(fd, buf, (size_t)ssize)) {
              /* TODO handle error gracefully ? signal to parent?*/
              perror("helper: write");
              goto exit;
            }
          size -= ssize;
        } while (size);
        close(fd);
        break;
      default:
        fprintf(stderr, "Unknown request\n");
        goto exit;
        break;
    }
  }

exit:
  close(fd);
exit_:
  //printf("exit %d query_count %d\n", getpid(), query_count);
  close(0);
  exit(0);
  //TODO send signal to parent and restart loop instead of exiting (maybe)
}

void terminate(int) {
  //printf("exit %d query_count %d\n", getpid(), query_count);
  close(0);
  exit(0);
}

<commit_msg>small bug in the fstat block of fdhelp.cc<commit_after>#include <tamer/fdhmsg.hh>
#include <signal.h>

void terminate(int);
int query_count = 0;

int main (void) {
  char buf[8192];
  int len;
  int fd;

  pid_t pid;
  int socks[2], chfd;

  fdh_msg * msg;

  char * fname;
  struct stat * stat;

  size_t size;
  ssize_t ssize;

  if (signal(SIGTERM, terminate) == SIG_ERR) {
    perror("unable to set signal");
    exit(0);
  }

  for (;;) {
    if ((len = fdh_recv(0, &fd, buf, sizeof(buf))) < 0) {
      perror("recvmsg");
      goto exit_;
    } else if (len == 0)
      goto exit_;

    query_count ++;
    msg = (fdh_msg *)buf;

    switch (msg->query.req) {
      case FDH_CLONE:
        if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0) {
          chfd = -1;
          msg->reply.err = errno;
          goto forkerr;
        }

        msg->reply.pid = pid = fork();
        if (pid < 0) {
          chfd = -1;
          msg->reply.err = errno;
          goto forkerr;
        } else if (pid == 0) {
          // child
          close(0);
          close(socks[0]);
          if (dup2(socks[1], 0) < 0) {
            close(socks[1]);
            goto exit_;
          }
          close(socks[1]);
          break;
        }

        chfd = socks[0];
        msg->reply.err = 0;
      forkerr:
        close(socks[1]);
        if (fdh_send(0, chfd, (char *)msg, FDH_MSG_SIZE) < 0) {
          perror("sendmsg");
          close(socks[0]);
          goto exit_;
        }
        close(socks[0]);
        break;
      case FDH_OPEN:
        fname = (char *)&buf[FDH_MSG_SIZE];
        msg->reply.err = ((fd =
              open(fname, msg->query.flags, msg->query.mode)) < 0) ? errno : 0;
        if (fdh_send(0, fd, (char *)msg, FDH_MSG_SIZE) < 0) {
          perror("sendmsg");
          goto exit;
        }
        close(fd);
        break;
      case FDH_STAT:
        stat = (struct stat *)&buf[FDH_MSG_SIZE];
        msg->reply.err = (fstat(fd, stat) < 0) ? errno : 0;
        if (fdh_send(0, -1, (char *)msg, FDH_MSG_SIZE + sizeof(struct stat)) < 0) {
          perror("sendmsg");
          goto exit;
        }
        close(fd);
        break;
      case FDH_READ:
        if (sendfile(0, fd, NULL, msg->query.size) < 0) {
          /* TODO handle error gracefully ?*/
          perror("sendfile");
          goto exit;
        }
        close(fd);
        break;
      case FDH_WRITE:
        size = msg->query.size;
        do {
          if ((ssize = read(0, buf, sizeof(buf))) < 0) {
            /* TODO handle error gracefully ? signal to parent?*/
            perror("helper: read");
            goto exit;
          } else if (ssize == 0)
            break;
          if (ssize)
            if (ssize != write(fd, buf, (size_t)ssize)) {
              /* TODO handle error gracefully ? signal to parent?*/
              perror("helper: write");
              goto exit;
            }
          size -= ssize;
        } while (size);
        close(fd);
        break;
      default:
        fprintf(stderr, "Unknown request\n");
        goto exit;
        break;
    }
  }

exit:
  close(fd);
exit_:
  //TODO send signal to parent and restart loop instead of exiting (maybe)
  terminate(0);
}

void terminate(int) {
  //printf("exit %d query_count %d\n", getpid(), query_count);
  close(0);
  exit(0);
}

<|endoftext|>


<commit_before><commit_msg>Usage + commandline options<commit_after><|endoftext|>


<commit_before>#include <sh/sh.hpp>
#include <sh/shutil.hpp>
#include <iostream>
#include <list>
#include "Shader.hpp"
#include "Globals.hpp"

using namespace SH;
using namespace ShUtil;

// VCS direction and up
ShVector3f lightDir;
ShVector3f lightUp;

class AlgebraWrapper: public Shader {
  public:
    AlgebraWrapper(std::string name, int lightidx, int surfidx, int postidx)
      : Shader(name), lightidx(lightidx), surfidx(surfidx), postidx(postidx) {}

    bool init();
    void render();

    ShProgram vertex() { return vsh;}
    ShProgram fragment() { return fsh;}

  private:
    int lightidx, surfidx, postidx;
    ShProgram vsh, fsh;
};

class AlgebraShader : public Shader {
public:
  AlgebraShader();
  ~AlgebraShader();

  bool init();

  ShProgram vertex() { return vsh;}
  ShProgram fragment() { return fsh;}

  ShProgram vsh, fsh;

  static bool init_all();

private:
  friend class AlgebraWrapper;

  static const int LIGHT = 3;
  static const int SURFACE = 6;
  static const int POST = 2;

  static ShProgram lightsh[LIGHT];
  static const char* lightName[LIGHT];

  static ShProgram surfsh[SURFACE];
  static const char* surfName[SURFACE];

  static ShProgram postsh[POST];
  static const char* postName[POST];

  typedef std::list<Shader*> ShaderList;
  static std::list<Shader*> shaders;
  static bool doneInit;
};

AlgebraShader::ShaderList AlgebraShader::shaders;
ShProgram AlgebraShader::lightsh[AlgebraShader::LIGHT];
ShProgram AlgebraShader::surfsh[AlgebraShader::SURFACE];
ShProgram AlgebraShader::postsh[AlgebraShader::POST];
bool AlgebraShader::doneInit = false;

const char* AlgebraShader::lightName[] = {
  "Point Light",
  "Spot Light",
  "Textured Hemispherical Light"
};

const char* AlgebraShader::surfName[] = {
  "Null Surface",
  "Diffuse Surface",
  "Specular Surface",
  "Phong Surface",
  "Textured Phong Surface",
  "Gooch Surface"
};

const char* AlgebraShader::postName[] = {
  "Null Postprocessor",
  "Halftone Postprocessor"
};

bool AlgebraWrapper::init() {
  AlgebraShader::init_all();
  ShProgram lightsh = AlgebraShader::lightsh[lightidx];
  ShProgram surfsh = AlgebraShader::surfsh[surfidx];
  ShProgram postsh = AlgebraShader::postsh[postidx];

  fsh = namedConnect(lightsh, surfsh);
  fsh = namedConnect(fsh, postsh);

  vsh = ShKernelLib::shVsh( Globals::mv, Globals::mvp );
  vsh = vsh << shExtract("lightPos") << Globals::lightPos;
  vsh = namedAlign(vsh, fsh);
  return true;
}

void AlgebraWrapper::render() {
  lightDir = -normalize(Globals::mv | Globals::lightDirW);
  ShVector3f horiz = cross(lightDir, ShConstant3f(0.0f, 1.0f, 0.0f));
  lightUp = cross(horiz, lightDir);

  // set up lighting crap
  Shader::render();
}

AlgebraShader::AlgebraShader()
  : Shader("Algebra: Algebra Parent")
{

  for(int i = 0; i < LIGHT; ++i) {
    for(int j = 0; j < SURFACE; ++j) {
      for(int k = 0; k < POST; ++k) {
        std::string name = std::string("Algebra: ") + lightName[i] + " - " + surfName[j] + " - " + postName[k];
        shaders.push_back(new AlgebraWrapper(name, i, j, k));
      }
    }
  }
}

AlgebraShader::~AlgebraShader()
{
  for(ShaderList::iterator I = shaders.begin(); I != shaders.end(); ++I) {
    delete *I;
  }
}

bool AlgebraShader::init() {
  // put together all the different combinations!
  vsh = ShKernelLib::shVsh( Globals::mv, Globals::mvp );
  vsh = vsh << shExtract("lightPos") << Globals::lightPos;

  std::cout << "AlgebraShader::init()" << std::endl;
  fsh = surfsh[0];
  vsh = namedAlign(vsh, fsh);
  std::cout << "AlgebraShader::init() done" << std::endl;
  return true;
}

bool AlgebraShader::init_all()
{

  if( doneInit ) return true;
  doneInit = true;

  ShImage image;

  // useful globals
  ShColor3f SH_NAMEDECL(lightColor, "Light Colour") = ShConstant3f(1.0f, 1.0f, 1.0f);
  ShAttrib1f SH_NAMEDECL(falloff, "Light falloff angle") = ShConstant1f(0.35f);
  falloff.range(0.0f, M_PI);
  ShAttrib1f SH_NAMEDECL(lightAngle, "Light cutoff angle") = ShConstant1f(0.5f);
  lightAngle.range(0.0f, M_PI);

  // TODO handle lightDirection and light up properly
  ShColor3f SH_NAMEDECL(kd, "Diffuse Color") = ShConstant3f(1.0f, 0.5f, 0.7f);
  ShColor3f SH_NAMEDECL(ks, "Specular Color") = ShConstant3f(0.7f, 0.7f, 0.7f);
  ShColor3f SH_NAMEDECL(cool, "Specular Color") = ShConstant3f(0.4f, 0.4f, 1.0f);
  ShColor3f SH_NAMEDECL(warm, "Specular Color") = ShConstant3f(1.0f, 0.4f, 0.4f);
  ShAttrib1f SH_NAMEDECL(specExp, "Specular Exponent") = ShConstant1f(48.13f);
  specExp.range(0.0f, 256.0f);

// ****************** Make light shaders
  lightsh[0] = ShKernelLight::pointLight<ShColor3f>() << lightColor;
  lightsh[1] = ShKernelLight::spotLight<ShColor3f>() << lightColor << falloff << lightAngle << lightDir;

  ShAttrib1f SH_NAMEDECL(texLightScale, "Mask Scaling Factor") = ShConstant1f(5.0f);
  texLightScale.range(1.0f, 10.0f);
  image.loadPng(SHMEDIA_DIR "/mats/inv_oriental038.png");
  ShTexture2D<ShColor3f> lighttex(image.width(), image.height());
  lighttex.memory(image.memory());
  lightsh[2] = ShKernelLight::texLight2D(lighttex) << texLightScale << lightAngle << lightDir << lightUp;

  //lightsh[1] = ShKernelLight::spotLight(ShColor3f>() << lightColor << falloff << lightAngle << lightDir;
  //lightName[1] = "Spot Light";

// ****************** Make surface shaders
  surfsh[0] = ShKernelSurface::null<ShColor3f>();
  surfsh[1] = ShKernelSurface::diffuse<ShColor3f>() << kd;
  surfsh[2] = ShKernelSurface::specular<ShColor3f>() << ks << specExp;
  surfsh[3] = ShKernelSurface::phong<ShColor3f>() << kd << ks << specExp;

  image.loadPng(SHMEDIA_DIR "/textures/rustkd.png");
  ShTexture2D<ShColor3f> difftex(image.width(), image.height());
  difftex.memory(image.memory());

  image.loadPng(SHMEDIA_DIR "/textures/rustks.png");
  ShTexture2D<ShColor3f> spectex(image.width(), image.height());
  spectex.memory(image.memory());

  surfsh[4] = ShKernelSurface::phong<ShColor3f>() << ( access(difftex) & access(spectex) );
  surfsh[4] = surfsh[4] << shExtract("specExp") << specExp;
  surfsh[5] = ShKernelSurface::gooch<ShColor3f>() << kd << cool << warm;

// ******************* Make postprocessing shaders
  image.loadPng(SHMEDIA_DIR "/textures/halftone.png");
  ShTexture2D<ShColor3f> halftoneTex(image.width(), image.height());
  halftoneTex.memory(image.memory());

  ShAttrib1f SH_NAMEDECL(halftoneScale, "Scaling Factor") = ShConstant1f(0.005f);
  halftoneScale.range(0.001f, 0.010f);

  postsh[0] = keep<ShColor3f>("result");
  postsh[1] = ShKernelPost::halftone<ShColor3f>(halftoneTex) << halftoneScale;

  return true;
}

AlgebraShader the_algebra_shader;

<commit_msg>fixed halftoning in a way<commit_after>#include <sh/sh.hpp>
#include <sh/shutil.hpp>
#include <iostream>
#include <list>
#include "Shader.hpp"
#include "Globals.hpp"
#include "ShrikeCanvas.hpp"

using namespace SH;
using namespace ShUtil;

// VCS direction and up
ShVector3f lightDir;
ShVector3f lightUp;
ShAttrib1f width;
ShAttrib1f invwidth;
ShAttrib1f height;
ShAttrib1f invheight;

class AlgebraWrapper: public Shader {
  public:
    AlgebraWrapper(std::string name, int lightidx, int surfidx, int postidx)
      : Shader(name), lightidx(lightidx), surfidx(surfidx), postidx(postidx) {}

    bool init();
    void render();

    ShProgram vertex() { return vsh;}
    ShProgram fragment() { return fsh;}

  private:
    int lightidx, surfidx, postidx;
    ShProgram vsh, fsh;
};

class AlgebraShader : public Shader {
public:
  AlgebraShader();
  ~AlgebraShader();

  bool init();

  ShProgram vertex() { return vsh;}
  ShProgram fragment() { return fsh;}

  ShProgram vsh, fsh;

  static bool init_all();

private:
  friend class AlgebraWrapper;

  static const int LIGHT = 3;
  static const int SURFACE = 6;
  static const int POST = 2;

  static ShProgram lightsh[LIGHT];
  static const char* lightName[LIGHT];

  static ShProgram surfsh[SURFACE];
  static const char* surfName[SURFACE];

  static ShProgram postsh[POST];
  static const char* postName[POST];

  typedef std::list<Shader*> ShaderList;
  static std::list<Shader*> shaders;
  static bool doneInit;
};

AlgebraShader::ShaderList AlgebraShader::shaders;
ShProgram AlgebraShader::lightsh[AlgebraShader::LIGHT];
ShProgram AlgebraShader::surfsh[AlgebraShader::SURFACE];
ShProgram AlgebraShader::postsh[AlgebraShader::POST];
bool AlgebraShader::doneInit = false;

const char* AlgebraShader::lightName[] = {
  "Point Light",
  "Spot Light",
  "Textured Hemispherical Light"
};

const char* AlgebraShader::surfName[] = {
  "Null Surface",
  "Diffuse Surface",
  "Specular Surface",
  "Phong Surface",
  "Textured Phong Surface",
  "Gooch Surface"
};

const char* AlgebraShader::postName[] = {
  "Null Postprocessor",
  "Halftone Postprocessor"
};

bool AlgebraWrapper::init() {
  AlgebraShader::init_all();
  ShProgram lightsh = AlgebraShader::lightsh[lightidx];
  ShProgram surfsh = AlgebraShader::surfsh[surfidx];
  ShProgram postsh = AlgebraShader::postsh[postidx];

  fsh = namedConnect(lightsh, surfsh);
  fsh = namedConnect(fsh, postsh);

  vsh = ShKernelLib::shVsh( Globals::mv, Globals::mvp );
  vsh = vsh << shExtract("lightPos") << Globals::lightPos;
  vsh = namedAlign(vsh, fsh);
  return true;
}

void AlgebraWrapper::render() {
  lightDir = -normalize(Globals::mv | Globals::lightDirW);
  ShVector3f horiz = cross(lightDir, ShConstant3f(0.0f, 1.0f, 0.0f));
  lightUp = cross(horiz, lightDir);

  const ShrikeCanvas *canvas = ShrikeCanvas::instance();
  width = canvas->m_width;
  invwidth = 1.0f / width;
  height = canvas->m_height;
  invheight = 1.0f / height;

  // set up lighting crap
  Shader::render();
}

AlgebraShader::AlgebraShader()
  : Shader("Algebra: Algebra Parent")
{

  for(int i = 0; i < LIGHT; ++i) {
    for(int j = 0; j < SURFACE; ++j) {
      for(int k = 0; k < POST; ++k) {
        std::string name = std::string("Algebra: ") + lightName[i] + " - " + surfName[j] + " - " + postName[k];
        shaders.push_back(new AlgebraWrapper(name, i, j, k));
      }
    }
  }
}

AlgebraShader::~AlgebraShader()
{
  for(ShaderList::iterator I = shaders.begin(); I != shaders.end(); ++I) {
    delete *I;
  }
}

bool AlgebraShader::init() {
  // put together all the different combinations!
  vsh = ShKernelLib::shVsh( Globals::mv, Globals::mvp );
  vsh = vsh << shExtract("lightPos") << Globals::lightPos;

  std::cout << "AlgebraShader::init()" << std::endl;
  fsh = surfsh[0];
  vsh = namedAlign(vsh, fsh);
  std::cout << "AlgebraShader::init() done" << std::endl;
  return true;
}

bool AlgebraShader::init_all()
{

  if( doneInit ) return true;
  doneInit = true;

  ShImage image;

  // useful globals
  ShColor3f SH_NAMEDECL(lightColor, "Light Colour") = ShConstant3f(1.0f, 1.0f, 1.0f);
  ShAttrib1f SH_NAMEDECL(falloff, "Light falloff angle") = ShConstant1f(0.35f);
  falloff.range(0.0f, M_PI);
  ShAttrib1f SH_NAMEDECL(lightAngle, "Light cutoff angle") = ShConstant1f(0.5f);
  lightAngle.range(0.0f, M_PI);

  // TODO handle lightDirection and light up properly
  ShColor3f SH_NAMEDECL(kd, "Diffuse Color") = ShConstant3f(1.0f, 0.5f, 0.7f);
  ShColor3f SH_NAMEDECL(ks, "Specular Color") = ShConstant3f(0.7f, 0.7f, 0.7f);
  ShColor3f SH_NAMEDECL(cool, "Specular Color") = ShConstant3f(0.4f, 0.4f, 1.0f);
  ShColor3f SH_NAMEDECL(warm, "Specular Color") = ShConstant3f(1.0f, 0.4f, 0.4f);
  ShAttrib1f SH_NAMEDECL(specExp, "Specular Exponent") = ShConstant1f(48.13f);
  specExp.range(0.0f, 256.0f);

// ****************** Make light shaders
  lightsh[0] = ShKernelLight::pointLight<ShColor3f>() << lightColor;
  lightsh[1] = ShKernelLight::spotLight<ShColor3f>() << lightColor << falloff << lightAngle << lightDir;

  ShAttrib1f SH_NAMEDECL(texLightScale, "Mask Scaling Factor") = ShConstant1f(5.0f);
  texLightScale.range(1.0f, 10.0f);
  image.loadPng(SHMEDIA_DIR "/mats/inv_oriental038.png");
  ShTexture2D<ShColor3f> lighttex(image.width(), image.height());
  lighttex.memory(image.memory());
  lightsh[2] = ShKernelLight::texLight2D(lighttex) << texLightScale << lightAngle << lightDir << lightUp;

  //lightsh[1] = ShKernelLight::spotLight(ShColor3f>() << lightColor << falloff << lightAngle << lightDir;
  //lightName[1] = "Spot Light";

// ****************** Make surface shaders
  surfsh[0] = ShKernelSurface::null<ShColor3f>();
  surfsh[1] = ShKernelSurface::diffuse<ShColor3f>() << kd;
  surfsh[2] = ShKernelSurface::specular<ShColor3f>() << ks << specExp;
  surfsh[3] = ShKernelSurface::phong<ShColor3f>() << kd << ks << specExp;

  image.loadPng(SHMEDIA_DIR "/textures/rustkd.png");
  ShTexture2D<ShColor3f> difftex(image.width(), image.height());
  difftex.memory(image.memory());

  image.loadPng(SHMEDIA_DIR "/textures/rustks.png");
  ShTexture2D<ShColor3f> spectex(image.width(), image.height());
  spectex.memory(image.memory());

  surfsh[4] = ShKernelSurface::phong<ShColor3f>() << ( access(difftex) & access(spectex) );
  surfsh[4] = surfsh[4] << shExtract("specExp") << specExp;
  surfsh[5] = ShKernelSurface::gooch<ShColor3f>() << kd << cool << warm;

// ******************* Make postprocessing shaders
  image.loadPng(SHMEDIA_DIR "/textures/halftone.png");
  ShTexture2D<ShColor3f> halftoneTex(image.width(), image.height());
  halftoneTex.memory(image.memory());

  postsh[0] = keep<ShColor3f>("result");

  ShAttrib1f SH_NAMEDECL(htscale, "Scaling Factor") = ShConstant1f(50.0f);
  htscale.range(1.0f, 400.0f);
  postsh[1] = ShKernelPost::halftone<ShColor3f>(halftoneTex) << (mul<ShAttrib1f>() << htscale << invheight);

  return true;
}

AlgebraShader the_algebra_shader;

<|endoftext|>