from __future__ import with_statement

from django.db import transaction
from django.conf import settings

import os
import re

slug_regex = re.compile('[^a-z0-9_]')
migration_file_regex = re.compile('^(\d+)_([a-z0-9_]+)\.py$')

class Migration(object):
	def __init__(self):
		pass

	def create(self, name):
		from simplemigrations.template import migration_template

		new_filename = os.path.join(settings.MIGRATION_DIRECTORY, self.new_filename(name))

		with open(new_filename, "w") as f:
			f.write(migration_template)

		return new_filename

	def new_filename(self, name):
		slug_name = self.name_to_slug(name)
		num = self.max_migration() + 1
		return "%04d_%s.py" % (num, slug_name)

	def name_to_slug(self, name):
		name = name.lower().replace(' ', '_')
		return slug_regex.sub('', name)

	def files(self):
		return [f for f in os.listdir(settings.MIGRATION_DIRECTORY) \
			if os.path.isfile(os.path.join(settings.MIGRATION_DIRECTORY, f)) and migration_file_regex.match(f)]

	def migration_files(self):
		return [f for f in self.files() if migration_file_regex.match(f)]

	def migration_files_with_version(self):
		return [(f, int(migration_file_regex.match(f).groups()[0])) for f in self.migration_files()]

	def max_migration(self):
		nums = [t[1] for t in self.migration_files_with_version()]
		if len(nums):
			return max(nums)
		else:
			return 0

	def migrations_to_run(self):
		from simplemigrations.models import AppliedMigration
		latest_version = AppliedMigration.latest_version()
		return sorted([t for t in self.migration_files_with_version() if t[1] > latest_version], key=lambda x: x[1])

	def load_migration_model(self, file_path):
		import imp
		dir_name, file_name = os.path.split(file_path)
		mod_name = file_name.replace('.py', '')
		dot_py_suffix = ('.py', 'U', 1)
		mod = imp.load_module(mod_name, open(file_path), file_path, dot_py_suffix)
		return mod#.Migration

	@transaction.commit_manually
	def run(self):
		from simplemigrations.models import AppliedMigration

		for t in  self.migrations_to_run():
			file_name, version = t
			file_path = os.path.join(settings.MIGRATION_DIRECTORY, file_name)
			klass = self.load_migration_model(file_path)
			m = klass.Migration()

			m.run(action='up')
			AppliedMigration.objects.create(filename=file_name, version=version)
			transaction.commit()

	def redo(self):
		pass


@@ -1603,16 +1603,154 @@
  x%5B1%5D)%0A%0A
+%09def migration_file(self, version):%0A%09%09for t in self.migration_files_with_version():%0A%09%09%09if t%5B1%5D == version:%0A%09%09%09%09return t%5B0%5D%0A%09%09return None%0A%0A
 %09def loa
@@ -2016,19 +2016,8 @@
  mod
-#.Migration
 %0A%0A%09@
@@ -2064,64 +2064,8 @@
 f):%0A
-%09%09from simplemigrations.models import AppliedMigration%0A%0A
 %09%09fo
@@ -2242,16 +2242,217 @@
 _path)%0A%09
+%09%09self.migrate_up(klass, file_name, version)%0A%09%09%09transaction.commit()%0A%0A%09@transaction.autocommit%0A%09def migrate_up(self, klass, file_name, version):%0A%09%09from simplemigrations.models import AppliedMigration%0A%0A
 %09%09m = kl
@@ -2467,18 +2467,16 @@
 ation()%0A
-%0A%09
 %09%09m.run(
@@ -2488,17 +2488,16 @@
 n='up')%0A
-%09
 %09%09Applie
@@ -2553,33 +2553,72 @@
 sion=version)%0A%09%09
-%09
+#transaction.commit_unless_managed()%0A%0A%09@
 transaction.comm
@@ -2617,39 +2617,583 @@
 ion.
+auto
 commit
-()%0A%0A%09def redo(self):%0A%09%09pass
+%0A%09def migrate_down(self, klass, instance):%0A%09%09m = klass.Migration()%0A%09%09m.run(action='down')%0A%09%09instance.delete()%0A%09%09#transaction.commit_unless_managed()%0A%0A%09@transaction.commit_manually%0A%09def redo(self):%0A%09%09from simplemigrations.models import AppliedMigration%0A%0A%09%09am = AppliedMigration.latest()%0A%09%09version = am.version%0A%09%09file_name = self.migration_file(version)%0A%09%09file_path = os.path.join(settings.MIGRATION_DIRECTORY, file_name)%0A%09%09klass = self.load_migration_model(file_path)%0A%0A%09%09self.migrate_down(klass, am)%0A%09%09self.migrate_up(klass, file_name, version)%0A%0A%09%09transaction.commit()
 %0A%0A

split out migration process into migrate_up and migration_down for individual versions, filled in redo action