quizTypes.radio = [
  {
    questionCmpAmount: 4,
    probability: 10,
    type: 'Product contains 4 components',
    products: {from: 4, to: 8},
    minSimilarTags: 1,
    from: qB.prebuild.similarTaggedProducts.fn,
    question(income, log){
      return 'В какой из продуктов входят данные ингредиенты: '+income.uniq.map(a=> textFormat(a.name)).join(', ');//products.map(p=>p.title)
    },
    answer( income, log ){
      return shuffle(
        [new Answer.Correct(textFormat(income.correct.title))]
          .concat(income.wrong.map(p=>new Answer.Wrong(textFormat(p.title)))))
    }
  },
  {
    questionCmpAmount: 2,
    probability: 8,
    type: 'Component in product',
    products: {from: 4, to: 6},
    minSimilarTags: 1,
    from: qB.prebuild.similarTaggedProducts.fn,
    question(income, log){
      return `Выберите один ингредиент, который входит в продукт ${lapk(income.correct.title)}`
    },
    answer( income, log ){

      return shuffle(
        [new Answer.Correct(textFormat(shuffle(income.uniq)[0].name))]
          .concat(
            shuffle(
              qB.subdivideComponents( qB.getUniqComponents(income.wrong), income.correct.getComponents() )
            )
              .slice(0, rand(this.products.from-1, this.products.to-1))
              .map(c=>new Answer.Wrong(textFormat(c.name)))

          )
      )
    }
  },
  {
    questionCmpAmount: 0,
    probability: 8,
    type: 'Select product description',
    products: {from: 3, to: 5},
    minSimilarTags: 1,
    from: qB.prebuild.similarTaggedProducts.fn,
    question(income, log){
      return `Какое из этих описаний относится к продукту ${lapk(income.correct.title)}`
    },
    answer( income, log ){

      return shuffle(
        [new Answer.Correct(textFormat(income.correct.description))]
          .concat(
            income.wrong.map(
              p => new Answer.Wrong(textFormat(p.description))
            )
          ))
    }
  },
  {
    questionCmpAmount: 0,
    probability: 8,
    type: 'Select product that matches description',
    products: {from: 4, to: 6},
    minSimilarTags: 1,
    from: qB.prebuild.similarTaggedProducts.fn,
    question(income, log){
      return `К какому из продуктов относится это описание:\n${textFormat(income.correct.description)}`
    },
    answer( income, log ){

      return shuffle(
        [new Answer.Correct(textFormat(income.correct.title))]
          .concat(
            income.wrong.map(
              p => new Answer.Wrong(textFormat(p.title))
            )
          ))
    }
  },
  {
    probability: 10,
    answers: {from: 3, to: 6},

    question: ({product})=> `Выберите лишний ингредиент, НЕ входящий в продукт "${product.title}"`,
    type: 'Do not contain',
    from: (log)=>{
      const product = qB.randomProduct({ minComponents: 2, single: true }, log);
      return {baseProduct: product, product}

    },

    answer( {product}, log ){

      const out =
          shuffle(
            dP.Product.getComponents(product)
              .map(i=>({correct: false, text: i.name}))
          )
            .slice(0, rand(this.answers.from - 1, this.answers.to - 1)),

        // get tags
        tags = product.tags,

        donors = [];

      log.push(`Have ${dP.Product.getComponents(product).length} components. Took ${out.length}:`);
      out.forEach(function(a) {
        log.push('  > '+ a.text)
      });

      log.push('\nTags: '+dP.Product.getTags(product).map(t=>t.name).join(', '));

      Object.keys(dP.products)
        .map(k=>dP.products[k])
        .forEach(item => {
          if(item.id === product.id)
            return;

          const matchedCount = tags.filter(tid=>item.tags.indexOf(tid)>-1).length;
          if(matchedCount>0){
            donors.push({
              count: matchedCount,
              item,
              title: item.title,
              component: dP.Product.getComponents(item).map(a=>a.name)
            });
          }
        });

      log.push('Matched '+donors.length+' component donors.');

      donors.sort((a,b)=>b.count-a.count);
      if(!donors.length){
        log.push('Not enough');
        return false;
      }

      const maxCount = donors[0].count;
      const minCount = Math.round(maxCount - maxCount/4);
      const alreadyExist = out.reduce((store, i)=>{
        store[normalizeText(i.text)] = true;
        return store;
      }, {'соль': true,'сольпощово': true, 'сохор': true});

      log.push('Nearest candidate have got '+ maxCount +' similar tag.');

      const may = ([].concat.apply(
        [],
        donors
          .filter(i=>i.count > 0 && i.count >= minCount)
          .map(i=>
            i.component
              .filter(c=>{
                if(!c.trim())
                  return false;
                const normalized = normalizeText(c);
                if(normalized in alreadyExist)
                  return false;
                alreadyExist[normalized] = true;
                return true;
              })
              .map(x => ({count: i.count, item: i.item, text: x}))
          )
      ));

      log.push('Filtered candidates with ['+ (minCount===maxCount? minCount : minCount+' - '+ maxCount) +'] similar tags.');

      if(may.length<2)
        return false;

      const answer = rand(may);

      log.push('Use '+ answer.item.title +' as donor.');
      log.push('Because it has '+ answer.count +' similar tags: '+ dP.Product.getTags(answer.item).map(t=>t.name).join(', '));

      out.push({correct: true, text: answer.text});

      log.push('\n << '+ answer.text);


      return out;
    }
  }];