import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU
import org.xml.sax.*
import javax.xml.parsers.SAXParserFactory

grailsHome = Ant.project.properties."environment.GRAILS_HOME"

includeTargets << new File ( "${grailsHome}/scripts/Bootstrap.groovy" )  

target('default': "Allows migration from Confluence by importing from Confluence XML format") {
    packageApp()
    classLoader = new URLClassLoader([classesDir.toURL()] as URL[], rootLoader)
    Thread.currentThread().setContextClassLoader(classLoader)    
    loadApp()
    configureApp()
	
    importConfluenceXML()
}

target(importConfluenceXML: "The implementation task") {
	if(args) {
        def userClass = grailsApp.getDomainClass("org.grails.auth.User").clazz
        def adminUser = userClass.findByLogin("admin")
        if(!adminUser) {
            println "No admin users exists in the database, please run the application first so that the admin user can be setup"
            return
        }
        def file = new File(args.trim())
		if(file.exists()) {
			println "Loading XML, this can take a while..."
			def parser = SAXParserFactory.newInstance().newSAXParser()
			def handler = new SAXConfluenceParser()
			parser.parse(file, handler)
			println "Finished reading XML, importing to app.."
			handler.pages.eachWithIndex { page , i ->
					def wikiPageClass = grailsApp.getDomainClass("org.grails.wiki.WikiPage").clazz
					def wikiPage = wikiPageClass.newInstance(title:page.title, body:handler.bodies[i])
					try {
                        wikiPage.save(flush:true)
                        println "Saved ${wikiPage.title}"
                    } catch (Exception e) {
                        println "WARNING: Can't save page ${page.title}"
                        println e.message
                        return
                    }
					if(wikiPage.hasErrors()) {
						println "WARNING: Can't save page ${page.title}"
						wikiPage.errors.allErrors.each { println it }
					} else {
                        def v = wikiPage.createVersion()
                        v.author = adminUser
                        try {
                            v.save(flush:true)
                        } catch (Exception e) {
                            println "WARNING: Can't save version ${v.title} (${v.number})"
                        }
                    }

            }
			println "Import finished successfully."
		}
		else {
			println "File $args does not exist"
		}
	}
	else {
		println "Please specify confluence XML file"
	}
}
class SAXConfluenceParser extends  org.xml.sax.helpers.DefaultHandler {
	def pages = []
	def bodies = [:]
	def pageMode = false
	def propertyMode = false
	def bodyIdMode = false
	def captureBodyId = false
	def bodyMode = false
	def lastBodyId
	def lastBody = new StringBuffer()
	def captureBody = false
	def lastProperty
	void startElement(String uri, String localName, String qName, Attributes attributes) {
		if(qName == 'object') pageMode = false
		if(bodyIdMode && qName=='id') {
			captureBodyId = true
		}
		else if(bodyMode) {
			if(qName == 'id') {
				captureBodyId = true
			}
			if(qName == 'property' && 'body' == attributes.getValue('name')) {
				captureBody = true
			}
		}
		else if(pageMode) {		
			if(qName == 'property') {
				propertyMode = true
				lastProperty = attributes.getValue('name')
			}
			if(qName == 'collection' && 'bodyContents' == attributes.getValue('name')) {
				bodyIdMode = true
				pageMode = false
			}
		}
		else {
			def className = attributes.getValue('class')		
			if(qName == 'object' && 'Page' == className) {
				pages << [:]
				pageMode = true
			}		
			else if(qName == 'object' && 'BodyContent' == className) {
				bodyMode = true
			}	
		}
	}
	
	void endElement(String namespaceURI, String localName, String qName)  {
		if(bodyMode && captureBody && 'property' == qName) {
			def entry = bodies.find { key,val -> val == lastBodyId}
			if(entry) {
				entry.value = lastBody.toString()
			}
			
			bodyMode = false
			captureBody = false
			lastBodyId = null
			lastBody = new StringBuffer()			
		}
	}
	
	void characters(char[] ch,
	                       int start,
	                       int length) {
		if(propertyMode) {
			propertyMode = false
			if(lastProperty) {
				pages[-1]."$lastProperty" = String.copyValueOf(ch, start, length)
				lastProperty = null
			}
		}
		else if(bodyMode && captureBodyId) {
			lastBodyId = String.copyValueOf(ch, start, length)
			captureBodyId = false
		}
		else if(bodyMode && captureBody) {
			lastBody << String.copyValueOf(ch, start, length)
		}
		else if(bodyIdMode && captureBodyId) {
			def pageIndex = pages.size()-1
			def id = String.copyValueOf(ch, start, length).trim()
			if(id) {
				bodies[pageIndex] = id
				bodyIdMode = false
				captureBodyId = false
				pageMode=true				
			}
		}
	}
}