var isNode=new Function("try {return this===global;}catch(e){return false;}");
if (isNode()){
    var JSZip  = require('jszip');
    const { TextDecoder } = require('string_decoder');
    var generatedBufferType = 'uint8array'
} else {
    var generatedBufferType = 'uint8array'
}

class EpubXhtml{
    constructor(filename) {
        let name = filename.split('.')
        name[name.length-1] = 'xhtml'
        this.filename = name.join('.')
        this.mime = 'application/xhtml+xml'
    }

    convert(content){
        // var blob = new Blob([content],{type:'text/plain'});
        // var reader = new FileReader();
        // reader.onload = function(evt){callback(evt.target.result);};
        // reader.readAsText(blob, encoding);

        let cnt = `<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:epub="http://www.idpf.org/2007/ops">
<head>
  <title></title>
</head>
<body>
${new TextDecoder("utf-8").write(content)}
</body>
</html>
`
        return cnt
    }
}

class EpubOpf{
    constructor(filename, meta) {
        this.filename = filename
        this.meta = meta
    }

    generate(){
        let m = this.meta
        let cnt = `<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://www.idpf.org/2007/opf"
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         xmlns:dcterms="http://purl.org/dc/terms/"
         unique-identifier="pub-id"
         version="3.0">
  <metadata>
    <meta property="dcterms:modified">2013-03-22T12:24:00Z</meta>
    <dc:rights>Please read the legal notice included in this e-book and/or check the copyright status in your country.</dc:rights>
    <dc:identifier id="pub-id">${m.metadata.book_id}</dc:identifier>
    <dc:title>${m.metadata.title}</dc:title>
    <dc:language>${m.metadata.language}</dc:language>\n`

        if (m.metadata.publisher){
            cnt += `    <dc:publisher>${m.metadata.publisher}</dc:publisher>\n`
        }
        if (m.metadata.cover_image){
            cnt += `    <meta content="cover-image" name="${m.metadata.cover_image}"/>\n`
        }
		// <dc:creator opf:file-as="Greatness, Georgia's" opf:role="aut">Lauren Baratz-Logsted</dc:creator>

        cnt +='  </metadata>\n  <manifest>\n'

        for (let id in m.manifest){
            let f = m.manifest[id]
            if (f.hasOwnProperty('property')){
                cnt += `    <item id="${f.id}" media-type="${f.mime}" href="${f.filename}" properties="${f.property}"/>\n`
            }else{
                cnt += `    <item id="${f.id}" media-type="${f.mime}" href="${f.filename}"/>\n`
            }
        }
        cnt += `  </manifest>\n  <spine toc="${m.getId(m.ncx().filename)}">\n`
        for (let i in m.spine){
            cnt += `    <itemref idref="${m.spine[i]}" />\n`
        }
        cnt += '  </spine>\n  <guide>\n'
        cnt += `    <reference href="${m.nav().filename}" title="Table of Contents" type="toc"/>\n`
        cnt += '  </guide>\n</package>\n'
        return cnt
    }
}

class EpubNcx{
    constructor(filename, meta) {
        this.filename = filename
        this.meta = meta
        this.mime = 'application/x-dtbncx+xml'
    }

    generate(){
        let m = this.meta
        let cnt = `<?xml version="1.0" encoding="UTF-8"?>
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" xml:lang="en" version="2005-1">
<head>
  <meta name="dtb:uid" content="${m.metadata.book_id}"/>
  <meta name="dtb:depth" content="2"/>
  <meta name="dtb:totalPageCount" content="0"/>
  <meta name="dtb:maxPageNumber" content="0"/>
</head>
<docTitle>
    <text>${m.metadata.title}</text>
</docTitle>
<navMap>
`
        for (let i in this.meta.toc){
            let toc_item = this.meta.toc[i]
            cnt +=
             `  <navPoint class="chapter" id="navpoint-${i}" playOrder="${i}">\n`
            +`    <navLabel><text>${toc_item.label}</text></navLabel>\n`
            +`    <content src="${toc_item.filename}"/>\n`
            +'  </navPoint>\n'
        }

        cnt += '  </navMap>\n</ncx>\n'
        return cnt
    }
}

class EpubNav{
    constructor(filename, meta) {
        this.filename = filename
        this.meta = meta
        this.mime = 'application/xhtml+xml'
    }

    generate(){
        let m = this.meta
        let cnt = `<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:epub="http://www.idpf.org/2007/ops">
<head>
  <title>${m.metadata.title}</title>
</head>
<body>
  <h1>${m.metadata.title}</h1>
  <nav epub:type="toc" id="toc">
  <h2>Table Of Content</h2>
  <ol>
`
        for (let i in this.meta.toc){
            let toc_item = this.meta.toc[i]
            cnt += `  <li><a href="${toc_item.filename}">${toc_item.label}</a></li>\n`
        }

        cnt += '  </ol>\n  </nav>\n</body>\n</html>\n'
        return cnt
    }
}

class EpubMeta{
    constructor() {
        this.zip = new JSZip();

        this.metadata = {
            book_id: 'book_id',
            title: 'title',
            language: 'en',
            author: 'author',
            publisher: 'publisher',
            cover_image: 'cover.img'
        }
        this.manifest = {}
        this.spine = []
        this.guide = []
        this.toc = []
        this.override = {}

        this.addManifest(this.ncx().filename, this.ncx().mime)
        this.addManifest(this.nav().filename, this.nav().mime, 'nav')
        this.manifest[this.nav().filename].property = 'nav' //TODO
    }

    addBookId(book_id){
        this.metadata.book_id = book_id
    }
    addTitle(title){
        this.metadata.title = title
    }
    addAuthor(author){
        this.metadata.author = author
    }
    addPublisher(publisher){
        this.metadata.publisher = publisher
    }
    addLanguage(lang){
        this.metadata.language = lang
    }

    addMetaData(){
    }

    addManifest(filename, mime){
        let key = filename
        if (mime.startsWith('text/html')){
            let o = new EpubXhtml(filename)
            this.override[key] = o
            filename = o.filename
            mime = o.mime
        }
        let id = 'id_' + filename.replace(/[^a-z0-9]/gi, '_').toLowerCase()
        this.manifest[key] =
            {
                filename : filename,
                mime : mime,
                id : id
            }
    }

    getId(filename){
        return this.manifest[filename].id
    }

    addSpine(filename){
        this.spine.push(this.manifest[filename].id)
    }

    addCover(filename){
        this.manifest[filename].property = 'cover-image'
    }

    addToc(filename, label, depth){
        if (filename in this.override){
            filename = this.override[filename].filename
        }
        this.toc.push({
            filename: filename,
            label: label,
            depth: depth
        })
    }

    opf(){
        return new EpubOpf("content.opf", this)
    }

    ncx(){
        return new EpubNcx("content.ncx", this)
    }

    nav(){
        return new EpubNav("content.xhtml", this)
    }
}

class EpubWriter{
    constructor(book_id) {
        this.zip = new JSZip();
        this.meta = new EpubMeta();
        this.override = {}
        this.createEpubStruct();
    }

    createEpubStruct(){
        this.zip.file("mimetype", "application/epub+zip", {compression: "STORE"});
        this.zip.file("META-INF/container.xml",
`<?xml version='1.0' encoding='utf-8'?>
<container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
    <rootfiles>
    <rootfile media-type="application/oebps-package+xml" full-path="EPUB/content.opf"/>
    </rootfiles>
</container>
`       );
    }

    addFile(filename, content){
        console.log(`epub ${filename}: ${content}`)

        if (filename in this.meta.override){
            let o = this.meta.override[filename]
            filename = o.filename
            content = o.convert(content)
        }

        this.zip.file("EPUB/"+filename, content)
    }

    generateAsync(){
        this.addFile(this.meta.ncx().filename, this.meta.ncx().generate())
        this.addFile(this.meta.nav().filename, this.meta.nav().generate())
        this.addFile(this.meta.opf().filename, this.meta.opf().generate())
        return this.zip.generateAsync({
                type: generatedBufferType,
                compression: "DEFLATE"})
    }
}

if (isNode()){
    module.exports = EpubWriter
}
