import Blockly from 'blockly';
import {
  Cpp,
  ORDER_ADDITION,
  ORDER_ATOMIC,
  ORDER_DIVISION,
  ORDER_MULTIPLICATION,
  ORDER_RELATIONAL,
  ORDER_SUBTRACTION,
} from './cpp';

Cpp['flag_start'] = () => {
  return 'int main(int argc, char *argv[])';
};

Cpp['say'] = block => {
  Cpp.include['iostream'] = '#include <iostream>';
  const text = block.getFieldValue('text');
  // エスケープ処理
  const escaped = text.replace(/\\/g, '\\\\').replace(/\n/g, '\\\n').replace(/"/g, '\\"');
  return `std::cout << "${escaped}" << std::endl;\n`;
};

function defLoop(name: string, inputBlock: boolean) {
  Cpp[name] = block => {
    Cpp.include["cstdint"] = "#include <cstdint>";
    const i = Cpp.nameDB_.getDistinctName('i', Blockly.VARIABLE_CATEGORY_NAME);
    const program = Cpp.statementToCode(block, 'program');
    const arg0 = inputBlock ? Cpp.valueToCode(block, 'arg0', ORDER_RELATIONAL) : block.getFieldValue('arg0');
    const end = arg0 ? arg0 : '0';
    return `for (uint32_t ${i} = 0; ${i} < ${end}; ++${i}) {\n${program}}\n`;
  };
}
defLoop('loop-field', false);
defLoop('loop-block', true);

function defBinaryOperator(name: string, op: string, order: number) {
  Cpp[name] = block => {
    const arg0 = Cpp.valueToCode(block, 'arg0', order);
    const arg1 = Cpp.valueToCode(block, 'arg1', order);
    return [`${arg0} ${op} ${arg1}`, order];
  };
}
defBinaryOperator('add', '+', ORDER_ADDITION);
defBinaryOperator('sub', '-', ORDER_SUBTRACTION);
defBinaryOperator('mul', '*', ORDER_MULTIPLICATION);
defBinaryOperator('div', '/', ORDER_DIVISION);

Cpp['number'] = block => {
  const x = block.getFieldValue('arg0');
  return [x.toString(), ORDER_ATOMIC];
};
