import re
import warnings
from optparse import make_option
from django.core.management.commands.inspectdb import Command as InspectDBCommand
from django.db import connections, DEFAULT_DB_ALIAS
from salesforce.backend import introspection as sf_introspection
import django
import salesforce

class Command(InspectDBCommand):
	# This will export Salestorce to a valid models.py, if Django >=1.5.
	# It is recommended to use Django >=1.5 for inspectdb, even if the generated models.py will be used on Django <1.5
	# (The model generated by Django <=1.4 requires very much manual editing, adding many `related_name=...`)

	option_list = InspectDBCommand.option_list + (
		make_option('--table-filter', action='store', dest='table_name_filter',
			help='Regular expression that filters API Names of SF tables to introspect.'),
	)

	def handle_noargs(self, **options):
		if isinstance(options['table_name_filter'], str):
			options['table_name_filter'] = re.compile(options['table_name_filter']).match
		self.connection = connections[options['database']]
		if self.connection.vendor == 'salesforce':
			self.db_module = 'salesforce'
			for line in self.handle_inspection(options):
				line = line.replace(" Field renamed because it contained more than one '_' in a row.", "")
				line = re.sub(' #$', '', line)
				if django.VERSION[:2] < (1,5):
					# prevent problems with mutual dependencies etc.
					line = re.sub(r'(?<=models.ForeignKey\()(\w+)',  r"'\1'", line)
				elif django.VERSION[:2] == (1,5):
					# fix bug in Django 1.5
					line = line.replace("''self''", "'self'")
				self.stdout.write("%s\n" % line)
		else:
			super(Command, self).handle_noargs(**options)


	def get_field_type(self, connection, table_name, row):
		field_type, field_params, field_notes = super(Command, self
				).get_field_type(connection, table_name, row)
		if connection.vendor == 'salesforce':
			name, type_code, display_size, internal_size, precision, scale, null_ok, sf_params = row
			field_params.update(sf_params)
		return field_type, field_params, field_notes

	def normalize_col_name(self, col_name, used_column_names, is_relation):
		if self.connection.vendor == 'salesforce':
			beautified = re.sub('__c$', '', col_name)
			beautified = re.sub(r'([a-z0-9])(?=[A-Z])', r'\1_', beautified)
			beautified = beautified.lower()
			new_name, field_params, field_notes = super(Command, self
					).normalize_col_name(beautified, used_column_names, is_relation)
			# *reconstructed* : is what will SfField reconstruct to db column
			reconstructed = new_name.title().replace('_', '')
			if col_name.endswith('__c'):
				reconstructed += '__c'
				field_params['custom'] = True
			elif is_relation:
				reconstructed += 'Id'
			# TODO: Discuss whether 'db_column' should be rather compared case insensitive
			if reconstructed != col_name or 'db_column' in field_params:
				field_params['db_column'] = col_name
			if is_relation:
				if col_name in sf_introspection.last_with_important_related_name:
					field_params['related_name'] = '%s_%s_set' % (
							sf_introspection.last_introspected_model.lower(),
							new_name.replace('_', '')
							)
				if col_name in sf_introspection.last_read_only:
					field_params['sf_read_only'] = sf_introspection.last_read_only[col_name]
				field_params['on_delete'] = sf_introspection.SymbolicModelsName('DO_NOTHING')
		else:
			new_name, field_params, field_notes = super(Command, self
					).normalize_col_name(col_name, used_column_names, is_relation)
		return new_name, field_params, field_notes

	def get_meta(self, table_name):
		"""
		Return a sequence comprising the lines of code necessary
		to construct the inner Meta class for the model corresponding
		to the given database table name.
		"""
		ret =  ["    class Meta(models.Model.Meta):",
			"        db_table = '%s'" % table_name,
			]
		if self.connection.vendor == 'salesforce':
			for line in self.connection.introspection.get_additional_meta(table_name):
				ret.append("        " + line)
		ret.append("")
		return ret


if django.VERSION[:2] < (1,5):
	warnings.warn("Django >= 1.5 is required to generate a valid model. "
			"Manual editing is necessary for older Django.")
