00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef _OBBY_JUPITER_SERVER_HPP_
00020 #define _OBBY_JUPITER_SERVER_HPP_
00021
00022 #include <map>
00023 #include <net6/non_copyable.hpp>
00024 #include "operation.hpp"
00025 #include "record.hpp"
00026 #include "jupiter_algorithm.hpp"
00027 #include "jupiter_undo.hpp"
00028
00029 namespace obby
00030 {
00031
00034 template<typename Document>
00035 class jupiter_server: private net6::non_copyable
00036 {
00037 public:
00038 typedef Document document_type;
00039 typedef jupiter_algorithm<document_type> algorithm_type;
00040 typedef jupiter_undo<document_type> undo_type;
00041 typedef operation<document_type> operation_type;
00042 typedef record<document_type> record_type;
00043
00044 typedef sigc::signal<void, const record_type&, const user&, const user*>
00045 signal_record_type;
00046
00050 jupiter_server(document_type& doc);
00051 ~jupiter_server();
00052
00055 void client_add(const user& client);
00056
00059 void client_remove(const user& client);
00060
00065 void local_op(const operation_type& op, const user* from);
00066
00071 void remote_op(const record_type& rec, const user* from);
00072
00077 void undo_op(const user* from);
00078
00082 signal_record_type record_event() const;
00083 protected:
00084 typedef std::map<const user*, algorithm_type*> client_map;
00085
00086 client_map m_clients;
00087 document_type& m_document;
00088 undo_type m_undo;
00089
00090 signal_record_type m_signal_record;
00091 };
00092
00093 template<typename Document>
00094 jupiter_server<Document>::jupiter_server(document_type& doc):
00095 m_document(doc), m_undo(doc)
00096 {
00097 }
00098
00099 template<typename Document>
00100 jupiter_server<Document>::~jupiter_server()
00101 {
00102 for(typename client_map::iterator iter = m_clients.begin();
00103 iter != m_clients.end();
00104 ++ iter)
00105 {
00106 delete iter->second;
00107 }
00108 }
00109
00110 template<typename Document>
00111 void jupiter_server<Document>::client_add(const user& client)
00112 {
00113 if(m_clients.find(&client) != m_clients.end() )
00114 {
00115 throw std::logic_error(
00116 "obby::jupiter_server::client_add:\n"
00117 "Client has already been added"
00118 );
00119 }
00120
00121 m_clients[&client] = new algorithm_type;
00122 }
00123
00124 template<typename Document>
00125 void jupiter_server<Document>::client_remove(const user& client)
00126 {
00127 typename client_map::iterator iter = m_clients.find(&client);
00128 if(iter == m_clients.end() )
00129 {
00130 throw std::logic_error(
00131 "obby::jupiter_server::client_remove:\n"
00132 "Client has not been added"
00133 );
00134 }
00135
00136 delete iter->second;
00137 m_clients.erase(iter);
00138 }
00139
00140 template<typename Document>
00141 void jupiter_server<Document>::local_op(const operation_type& op,
00142 const user* from)
00143 {
00144 op.apply(m_document, from);
00145 m_undo.local_op(op, from);
00146
00147 for(typename client_map::iterator iter = m_clients.begin();
00148 iter != m_clients.end();
00149 ++ iter)
00150 {
00151 std::auto_ptr<record_type> rec = iter->second->local_op(op);
00152 m_signal_record.emit(*rec, *iter->first, from);
00153 }
00154 }
00155
00156 template<typename Document>
00157 void jupiter_server<Document>::remote_op(const record_type& rec,
00158 const user* from)
00159 {
00160 typename client_map::iterator iter = m_clients.find(from);
00161 if(iter == m_clients.end() )
00162 {
00163 throw std::logic_error(
00164 "obby::jupiter_server::remote_op:\n"
00165 "Client has not been added"
00166 );
00167 }
00168
00169 std::auto_ptr<operation_type> op = iter->second->remote_op(rec);
00170 op->apply(m_document, from);
00171 m_undo.remote_op(*op, from);
00172
00173 for(iter = m_clients.begin(); iter != m_clients.end(); ++ iter)
00174 {
00175 if(iter->first != from)
00176 {
00177 std::auto_ptr<record_type> rec =
00178 iter->second->local_op(*op);
00179
00180 m_signal_record.emit(*rec, *iter->first, from);
00181 }
00182 }
00183 }
00184
00185 template<typename Document>
00186 void jupiter_server<Document>::undo_op(const user* from)
00187 {
00188 std::auto_ptr<operation_type> op = m_undo.undo();
00189 op->apply(m_document, from);
00190
00191 for(typename client_map::iterator iter = m_clients.begin();
00192 iter != m_clients.end();
00193 ++ iter)
00194 {
00195 std::auto_ptr<record_type> rec = iter->second->local_op(*op);
00196 m_signal_record.emit(*rec, *iter->first, from);
00197 }
00198 }
00199
00200 template<typename Document>
00201 typename jupiter_server<Document>::signal_record_type
00202 jupiter_server<Document>::record_event() const
00203 {
00204 return m_signal_record;
00205 }
00206
00207 }
00208
00209 #endif // _OBBY_JUPITER_SERVER_HPP_