/*
 * Copyright 2010, Red Hat, Inc. and individual contributors as indicated by the
 * @author tags. See the copyright.txt file in the distribution for a full
 * listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This software is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
 * site: http://www.fsf.org.
 */
package org.zanata.tmx;

import java.io.InputStream;

import javax.persistence.EntityExistsException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import lombok.AllArgsConstructor;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import nu.xom.Element;

import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import javax.inject.Inject;
import javax.inject.Named;
import org.zanata.common.util.ElementBuilder;
import org.zanata.model.tm.TransMemory;
import org.zanata.transaction.TransactionUtil;
import org.zanata.util.RunnableEx;
import org.zanata.util.TMXParseException;
import org.zanata.xml.TmxDtdResolver;
import com.google.common.base.Throwables;

/**
 * Parses TMX input.
 *
 * @author Carlos Munoz <a
 *         href="mailto:camunoz@redhat.com">camunoz@redhat.com</a>
 */
@Named("tmxParser")

@Slf4j
public class TMXParser {
    // Batch size to commit in a new transaction for long files
    private static final int BATCH_SIZE = 100;

    @Inject
    private Session session;
    @Inject
    private TransMemoryAdapter transMemoryAdapter;

    public void parseAndSaveTMX(InputStream input, TransMemory transMemory)
            throws TMXParseException, SecurityException, IllegalStateException,
            RollbackException, HeuristicMixedException,
            HeuristicRollbackException, SystemException, NotSupportedException {
        int handledTUs = 0;
        try {
            log.info("parsing started for: {}", transMemory.getSlug());
            session.setFlushMode(FlushMode.MANUAL);
            session.setCacheMode(CacheMode.IGNORE);
            XMLInputFactory factory = XMLInputFactory.newInstance();
            factory.setProperty(XMLInputFactory.SUPPORT_DTD, true);
            factory.setProperty(XMLInputFactory.IS_VALIDATING, true);
            factory.setXMLResolver(new TmxDtdResolver());
            @Cleanup
            XMLStreamReader reader = factory.createXMLStreamReader(input);

            QName tmx = new QName("tmx");

            while (reader.hasNext()
                    && reader.next() != XMLStreamConstants.START_ELEMENT) {
            }
            if (!reader.hasNext())
                throw new TMXParseException("No root element");
            if (!reader.getName().equals(tmx))
                throw new TMXParseException("Wrong root element: expected tmx");

            // At this point, event = START_ELEMENT and name = tmx
            while (reader.hasNext()) {
                CommitBatch commitBatch =
                        new CommitBatch(reader, handledTUs, transMemory);
                TransactionUtil.get().runEx(commitBatch);
                handledTUs = commitBatch.handledTUs;
            }
        } catch (EntityExistsException e) {
            String msg =
                    "Possible duplicate TU (duplicate tuid or duplicate"
                            + "src content without tuid)";
            throw new TMXParseException(msg, e);
        } catch (Exception e) {
            Throwable rootCause = Throwables.getRootCause(e);
            if (rootCause instanceof TMXParseException) {
                throw (TMXParseException) e;
            } else if (rootCause instanceof XMLStreamException) {
                throw new TMXParseException(rootCause);
            } else {
                throw Throwables.propagate(e);
            }
        } finally {
            log.info("parsing stopped for: {}, TU count={}",
                    transMemory.getSlug(), handledTUs);
        }
    }



    @AllArgsConstructor
    private class CommitBatch implements RunnableEx {
        private XMLStreamReader reader;
        private int handledTUs;
        private TransMemory transMemory;
        private final QName header = new QName("header");
        private final QName tu = new QName("tu");

        @Override
        public void run() throws Exception {
            while (reader.hasNext() && handledTUs < BATCH_SIZE) {
                int eventType = reader.next();
                if (eventType == XMLStreamConstants.START_ELEMENT) {
                    QName elemName = reader.getName();
                    if (elemName.equals(tu)) {
                        Element tuElem = ElementBuilder.buildElement(reader);
                        transMemoryAdapter
                                .processTransUnit(transMemory, tuElem);
                        handledTUs++;
                    } else if (elemName.equals(header)) {
                        Element headerElem =
                                ElementBuilder.buildElement(reader);
                        transMemoryAdapter.processHeader(transMemory,
                                headerElem);
                    }
                }
            }
        }
    }

}

@@ -1314,50 +1314,8 @@
 on;%0A
-import javax.transaction.UserTransaction;%0A
 impo
@@ -3932,26 +3932,17 @@
 reader, 
-handledTUs
+0
 , transM
@@ -4034,16 +4034,17 @@
 dledTUs 
++
 = commit

fix TMXParser running into infinite loop