GPL + CeCILL Header change
[scilab.git] / scilab / modules / scicos / src / cpp / view_scilab / BaseAdapter.hxx
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014-2014 - Scilab Enterprises - Clement DAVID
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  * === LICENSE_END ===
14  *
15  */
16
17 #ifndef BASEADAPTER_HXX_
18 #define BASEADAPTER_HXX_
19
20 #include <cstring>
21
22 #include <algorithm>
23 #include <string>
24 #include <vector>
25 #include <sstream>
26
27 #include "bool.hxx"
28 #include "double.hxx"
29 #include "user.hxx"
30 #include "int.hxx"
31 #include "internal.hxx"
32 #include "tlist.hxx"
33 #include "mlist.hxx"
34 #include "string.hxx"
35 #include "callable.hxx"
36 #include "overload.hxx"
37 #include "configvariable.hxx"
38 #include "exp.hxx"
39
40 #include "view_scilab/Adapters.hxx"
41 #include "controller_helpers.hxx"
42 #include "utilities.hxx"
43 #include "Controller.hxx"
44 #include "model/BaseObject.hxx"
45
46 extern "C" {
47 #include "localization.h"
48 }
49
50 namespace org_scilab_modules_scicos
51 {
52 namespace view_scilab
53 {
54
55 /**
56  * A property used as a getter/setter for a specific name
57  */
58 template<typename Adaptor>
59 struct property
60 {
61 public:
62     typedef types::InternalType* (*getter_t)(const Adaptor& adaptor, const Controller& controller);
63     typedef bool (*setter_t)(Adaptor& adaptor, types::InternalType* v, Controller& controller);
64
65     typedef std::vector< property<Adaptor> > props_t;
66     typedef typename props_t::iterator props_t_it;
67
68
69     property(const std::wstring& prop, getter_t g, setter_t s) : original_index(fields.size()), name(prop), get(g), set(s) {};
70     ~property() {};
71
72     size_t original_index;
73     std::wstring name;
74     getter_t get;
75     setter_t set;
76
77     bool operator< (const std::wstring& v) const
78     {
79         return name < v;
80     }
81
82     static bool original_index_cmp(property<Adaptor> p1, property<Adaptor> p2)
83     {
84         return p1.original_index < p2.original_index;
85     }
86
87     /*
88      * Static properties accessors
89      */
90     static props_t fields;
91
92     /**
93      * @return true if the properties have already been setup, false otherwise.
94      */
95     static bool properties_have_not_been_set()
96     {
97         return fields.empty();
98     }
99
100     /**
101      * Add a property to an Adaptor
102      */
103     static void add_property(const std::wstring& name, getter_t g, setter_t s)
104     {
105         property<Adaptor>::props_t_it pos = std::lower_bound(fields.begin(), fields.end(), name);
106         fields.insert(pos, property(name, g, s));
107     }
108 };
109
110 /**
111  * Base definition of the adapter pattern, implement the get / set dispatch.
112  *
113  * Note that sub-classes are responsible to fill the fields accordingly to theirs interfaces.
114  */
115 template<typename Adaptor, typename Adaptee>
116 class BaseAdapter : public types::UserType
117 {
118
119 public:
120     BaseAdapter() : m_adaptee(nullptr) {};
121     BaseAdapter(const Controller& /*c*/, Adaptee* adaptee) : m_adaptee(adaptee) {}
122     BaseAdapter(const BaseAdapter& adapter) : BaseAdapter(adapter, true) {}
123     BaseAdapter(const BaseAdapter& adapter, bool cloneChildren) : m_adaptee(nullptr)
124     {
125         Controller controller;
126         ScicosID id = controller.cloneObject(adapter.getAdaptee()->id(), cloneChildren, true);
127         m_adaptee = controller.getObject< Adaptee >(id);
128     };
129     ~BaseAdapter()
130     {
131         if (m_adaptee != nullptr)
132         {
133             Controller controller;
134             controller.deleteObject(m_adaptee->id());
135         }
136     };
137
138     /*
139      * property accessors
140      */
141
142     bool hasProperty(const std::wstring& _sKey) const
143     {
144         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
145         return found != property<Adaptor>::fields.end() && !(_sKey < found->name);
146     }
147
148     types::InternalType* getProperty(const std::wstring& _sKey, Controller controller = Controller()) const
149     {
150         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
151         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
152         {
153             return found->get(static_cast<Adaptor*>(this), controller);
154         }
155         return 0;
156     }
157
158     bool setProperty(const std::wstring& _sKey, types::InternalType* v, Controller controller = Controller())
159     {
160         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), _sKey);
161         if (found != property<Adaptor>::fields.end() && !(_sKey < found->name))
162         {
163             return found->set(*static_cast<Adaptor*>(this), v, controller);
164         }
165         return false;
166     }
167
168     /**
169      * property as TList accessors
170      */
171
172     types::InternalType* getAsTList(types::TList* tlist, const Controller& controller)
173     {
174         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
175         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
176
177         // create the header
178         types::String* header = new types::String(1, 1 + (int)properties.size());
179         header->set(0, Adaptor::getSharedTypeStr().c_str());
180         int index = 1;
181         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
182         {
183             header->set(index, it->name.c_str());
184         }
185         tlist->append(header);
186
187         // set the tlist field value
188         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
189         {
190             types::InternalType* field = it->get(*static_cast<Adaptor*>(this), controller);
191             tlist->append(field);
192             if (field->isList())
193             {
194                 field->killMe();
195             }
196         }
197
198         return tlist;
199     }
200
201     bool setAsTList(types::InternalType* v, Controller& controller)
202     {
203         if (v->getType() != types::InternalType::ScilabTList && v->getType() != types::InternalType::ScilabMList)
204         {
205             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong type for field %s: Tlist or Mlist expected.\n"), Adaptor::getSharedTypeStr().c_str());
206             return false;
207         }
208         types::TList* current = v->getAs<types::TList>();
209         // The input TList cannot be empty
210         if (current->getSize() < 1)
211         {
212             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for field %s: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
213             return false;
214         }
215
216         // Check the header
217         types::String* header = current->getFieldNames();
218         if (header->getSize() < 1)
219         {
220             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong length for header of field %s: at least %d element expected.\n"), Adaptor::getSharedTypeStr().c_str(), 1);
221             return false;
222         }
223         // Make sure it is the same type as the Adapter
224         if (header->get(0) != Adaptor::getSharedTypeStr())
225         {
226             get_or_allocate_logger()->log(LOG_ERROR, _("Wrong value for header of field %s: %s expected.\n"), Adaptor::getSharedTypeStr().c_str(), Adaptor::getSharedTypeStr().c_str());
227             return false;
228         }
229
230         // Retrieve the Adapter's properties
231         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
232
233         // For each input property, if it corresponds to an Adapter's property, set it.
234         for (int index = 1; index < header->getSize(); ++index)
235         {
236             typename property<Adaptor>::props_t_it found = std::lower_bound(properties.begin(), properties.end(), header->get(index));
237             if (found != properties.end() && !(header->get(index) < found->name))
238             {
239                 bool status = found->set(*static_cast<Adaptor*>(this), current->get(index), controller);
240                 if (!status)
241                 {
242                     return false;
243                 }
244             }
245         }
246
247         return true;
248     }
249
250     /**
251      * property comparison
252      */
253
254     types::Bool* equal(types::UserType*& ut) override final
255     {
256         const Adapters::adapters_index_t adapter_index = Adapters::instance().lookup_by_typename(ut->getShortTypeStr());
257         // Check that 'ut' is an Adapter of the same type as *this
258         if (adapter_index == Adapters::INVALID_ADAPTER)
259         {
260             return new types::Bool(false);
261         }
262         if (this->getTypeStr() != ut->getTypeStr())
263         {
264             return new types::Bool(false);
265         }
266
267         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
268         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
269
270         types::Bool* ret = new types::Bool(1, 1 + properties.size());
271         ret->set(0, true); // First field is just the Adapter's name, which has been checked by the above conditions
272
273         Controller controller;
274         int index = 1;
275         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++index)
276         {
277             types::InternalType* ith_prop1 = it->get(*static_cast<Adaptor*>(this), controller);
278             types::InternalType* ith_prop2 = it->get(*static_cast<Adaptor*>(ut), controller);
279             ret->set(index, *ith_prop1 == *ith_prop2);
280
281             // Getting a property allocates data, so free it
282             ith_prop1->killMe();
283             ith_prop2->killMe();
284         }
285
286         return ret;
287     }
288
289     /**
290      * @return the Adaptee
291      */
292     Adaptee* getAdaptee() const
293     {
294         return m_adaptee;
295     }
296
297     /*
298      * All following methods should be implemented by each template instance
299      */
300
301     virtual std::wstring getTypeStr() = 0;
302     virtual std::wstring getShortTypeStr() = 0;
303
304 private:
305     virtual UserType* clone() override final
306     {
307         return new Adaptor(*static_cast<Adaptor*>(this));
308     }
309
310     /*
311      * Implement a specific types::User
312      */
313
314     bool isAssignable() override final
315     {
316         return true;
317     }
318
319     bool extract(const std::wstring & name, types::InternalType *& out) override final
320     {
321         typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
322         if (found != property<Adaptor>::fields.end() && !(name < found->name))
323         {
324             Controller controller;
325             types::InternalType* value = found->get(*static_cast<Adaptor*>(this), controller);
326             if (value == 0)
327             {
328                 return false;
329             }
330
331             out = value;
332             return true;
333         }
334
335         // specific case : to ease debugging let the user retrieve the model ID
336         if (name == L"modelID")
337         {
338             out = new types::Int64(m_adaptee->id());
339             return true;
340         }
341
342         return false;
343     }
344
345     types::InternalType* extract(types::typed_list* _pArgs) override final
346     {
347         if (_pArgs->size() == 0)
348         {
349             // call overload
350             return NULL;
351         }
352
353         if ((*_pArgs)[0]->isString())
354         {
355             types::String* pStr = (*_pArgs)[0]->getAs<types::String>();
356             types::InternalType* pOut = NULL;
357             extract(std::wstring(pStr->get(0)), pOut);
358             return pOut;
359         }
360         else
361         {
362             if ((*_pArgs)[0]->isDouble())
363             {
364                 types::Double* index = (*_pArgs)[0]->getAs<types::Double>();
365
366                 if (index->get(0) == 1)
367                 {
368                     // When _pArgs is '1', return the list of the property names of the Adaptor
369
370                     // Sort the properties before extracting them
371                     typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
372                     std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
373
374                     // Allocate the return
375                     types::String* pOut = new types::String(1, static_cast<int>(properties.size()));
376
377                     int i = 0;
378                     for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it, ++i)
379                     {
380                         pOut->set(i, it->name.data());
381                     }
382                     return pOut;
383                 }
384             }
385             else
386             {
387                 // TO DO : management other type for arguments like a scalar or matrix of double
388             }
389         }
390
391         return NULL;
392     }
393
394     types::UserType* insert(types::typed_list* _pArgs, types::InternalType* _pSource) override final
395     {
396         for (size_t i = 0; i < _pArgs->size(); i++)
397         {
398             if ((*_pArgs)[i]->isString())
399             {
400                 types::String* pStr = (*_pArgs)[i]->getAs<types::String>();
401                 std::wstring name = pStr->get(0);
402
403                 Controller controller;
404                 typename property<Adaptor>::props_t_it found = std::lower_bound(property<Adaptor>::fields.begin(), property<Adaptor>::fields.end(), name);
405                 if (found != property<Adaptor>::fields.end() && !(name < found->name))
406                 {
407                     found->set(*static_cast<Adaptor*>(this), _pSource, controller);
408                 }
409
410                 return this;
411             }
412             else
413             {
414                 return NULL;
415             }
416         }
417
418         // call overload
419         return NULL;
420     }
421
422     void whoAmI(void) override
423     {
424         std::cout << "scicos object";
425     }
426
427     bool hasToString() override final
428     {
429         // Do not allow scilab to call toString of this class
430         return false;
431     }
432
433     bool toString(std::wostringstream& ostr) override final
434     {
435         // Deprecated, use the overload instead
436         typename property<Adaptor>::props_t properties = property<Adaptor>::fields;
437         std::sort(properties.begin(), properties.end(), property<Adaptor>::original_index_cmp);
438
439         ostr << L"scicos_" <<  getTypeStr() << L" type :" << std::endl;
440         for (typename property<Adaptor>::props_t_it it = properties.begin(); it != properties.end(); ++it)
441         {
442             ostr << L"  " << it->name << std::endl;
443         }
444         return true;
445     }
446
447     bool isInvokable() const override final
448     {
449         return true;
450     }
451
452     bool invoke(types::typed_list & in, types::optional_list & /*opt*/, int /*_iRetCount*/, types::typed_list & out, const ast::Exp & e) override final
453     {
454         if (in.size() == 0)
455         {
456             out.push_back(this);
457             return true;
458         }
459         else if (in.size() == 1)
460         {
461             types::InternalType* _out = nullptr;
462             types::InternalType*  arg = in[0];
463             if (arg->isString())
464             {
465                 types::String* pString = arg->getAs<types::String>();
466                 for (int i = 0; i < pString->getSize(); ++i)
467                 {
468                     if (!extract(pString->get(i), _out))
469                     {
470                         return false;
471                     }
472                     out.push_back(_out);
473                 }
474             }
475
476             if (!out.empty())
477             {
478                 return true;
479             }
480         }
481
482         types::Callable::ReturnValue ret;
483         // Overload of extraction needs the BaseAdapter from where we extract
484         this->IncreaseRef();
485         in.push_back(this);
486
487         try
488         {
489             ret = Overload::call(L"%" + getShortTypeStr() + L"_e", in, 1, out);
490         }
491         catch (ast::InternalError & /*se*/)
492         {
493             ret = Overload::call(L"%l_e", in, 1, out);
494         }
495
496         // Remove this from "in" to keep "in" unchanged.
497         this->DecreaseRef();
498         in.pop_back();
499
500         if (ret == types::Callable::Error)
501         {
502             throw ast::InternalError(ConfigVariable::getLastErrorMessage(), ConfigVariable::getLastErrorNumber(), e.getLocation());
503         }
504
505         return true;
506     }
507
508 private:
509     Adaptee* m_adaptee;
510 };
511
512
513 } /* namespace view_scilab */
514 } /* namespace org_scilab_modules_scicos */
515
516 #endif /* BASEADAPTER_HXX_ */