text: const Promise = require('bluebird');
  const Collection = require('./Collection');
  
  function getValidFinalFactoryName(config, options) {
    const factoryNameInOptions = typeof options == 'object'?options._factoryName:undefined;
    const factoryNameInConfig = config?config.factoryName:undefined;
    const finalFactoryName = factoryNameInOptions || factoryNameInConfig;
  
    if (!finalFactoryName) {
      throw new Error('A valid factory name should be provided for association in factory ');
    }
  
    if (factoryNameInOptions) {
      delete options._factoryName;
    }
    return finalFactoryName;
  }
  
  function clone(object) {
    if (object instanceof Collection) {
      return object;
    } else if (Array.isArray(object)) {
      return object.map(clone);
    } else if (typeof object == 'object') {
      if (object === null) {
        return null;
      }
      if (object instanceof Date) {
        return new Date(object);
      }
  
      const objectConed = {};
  
      for (const key in object) {
        objectConed[key] = clone(object[key]);
      }
      return objectConed;
    } else {
      return object;
    }
  
  }
  
  function getIfSavedAtttribute(saved, phrase) {
    const isASavedPhrase = typeof phrase == 'string' && phrase.charAt(0)=='$';
  
    if (!isASavedPhrase) {
      return phrase;
    }
    const cleanPhras = phrase.slice(1);
    const splited = cleanPhras.split('.');
    const savedAs = splited[0];
    const savedModel = saved[savedAs];
  
    if (!savedModel) {
      throw new Error('No definition saved with name '+ savedAs);
    }
  
    let finalValue = savedModel;
    const regexp = /([^\(\)]+)(\(.*\)$)?/;
  
    try {
      for (let i = 1; i<splited.length;i++) {
        const match = regexp.exec(splited[i]);
  
        if (!match) {
          throw new Error('Sintaxis error in phrase ' + phrase);
        }
        finalValue = finalValue[match[1]];
        const isFunctionCall = match[2] != undefined;
  
        if (isFunctionCall) {
          if (!finalValue) {
            throw new Error('Invalid name : ' + match[1] + ' function');
          }
          const args = match[2].slice(1, -1).split(',');
  
          finalValue = finalValue.apply(null, args);
        }
      }
    } catch (err) {
      throw new Error('Error while obtaining value from saved object using phrase ' + phrase);
    }
  
    return finalValue;
  
  }
  module.exports = {
    clone: clone,
  
    getIfSavedAtttribute: getIfSavedAtttribute,
  
    getArrayOfOptionsFromObject: (object) => {
      if (typeof object._size!='number') {
        throw new Error('A valid size must be provided with the key _size');
      }
      const size = object._size;
      const prefix = object.$;
      const arrayOptions = [];
  
      delete object._size;
  
      for (let i=0; i<size; i++) {
        if (prefix) {
          object.$= prefix+i;
        }
        arrayOptions.push(clone(object));
      }
  
      return arrayOptions;
    },
  
    //Quiza en factory
    generateFromOptionsObject: (method, factory, optionsObject, associationConfig, saved) => {
      //Allow options using saved
      optionsObject = getIfSavedAtttribute(saved, optionsObject);
  
      //Allow creation by id
      const assingedById = typeof optionsObject === 'number';
  
      if (assingedById) {
        return Promise.resolve(optionsObject);
      }
  
      //Create from object
      factoryName = getValidFinalFactoryName(associationConfig, optionsObject);
  
      const definition = factory.createDefinitionFromTemplate(factoryName, optionsObject);
  
      return definition[method](saved)
        .then((modelAssociated) => {
          return modelAssociated.id;
        });
    },
  
    generateFromOptionsObjectAfter: (method, factory, optionsObject, associationConfig, createdInstance, saved) => {
      //Allow options using saved
      optionsObject = getIfSavedAtttribute(saved, optionsObject);
  
      //Not Allow creation by id
      const assingedById = typeof optionsObject === 'number';
  
      if (assingedById) {
        throw new Error('Ids can not be passed in '+associationConfig.as+' since it is a HasOne or HasMany association.');
      }
  
      //Create from object
      factoryName = getValidFinalFactoryName(associationConfig, optionsObject);
      if (!optionsObject) {
        optionsObject= {};
      }
      optionsObject[associationConfig.foreignKey] = createdInstance.id;
  
      const definition = factory.createDefinitionFromTemplate(factoryName, optionsObject);
  
      return definition[method](saved)
        .then((modelAssociated) => {
          return modelAssociated.id;
        });
    }
  };
  