/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jena.tdb2.store;

import java.io.StringReader ;
import java.util.Iterator;

import org.apache.jena.atlas.iterator.Iter ;
import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.StrUtils ;
import org.apache.jena.dboe.base.file.Location;
import org.apache.jena.system.Txn;
import org.apache.jena.dboe.transaction.txn.TransactionException;
import org.apache.jena.query.Dataset ;
import org.apache.jena.query.ReadWrite;
import org.apache.jena.rdf.model.Model ;
import org.apache.jena.rdf.model.Statement;
import org.apache.jena.riot.Lang ;
import org.apache.jena.riot.RDFDataMgr ;
import org.apache.jena.sparql.core.Quad;
import org.apache.jena.tdb2.TDB2Factory;
import org.apache.jena.tdb2.sys.TDBInternal;
import org.junit.After ;
import org.junit.Before ;
import org.junit.Test ;

/** Transactions and store connections - extended tests assuming the
 * basics work. Hence these tests use memory databases. 
 * 
 * For tests of StoreConnection basics:
 * @see AbstractTestStoreConnectionBasics
 * @see TestStoreConnectionDirect
 * @see TestStoreConnectionMapped
 * @see TestStoreConnectionMem
 */
public class TestTransactions
{
    // Per-test unique-ish.
    static int count = 0 ;
    long x = System.currentTimeMillis()+(count++) ;
    
    String ns = "http://example/TestTransactions#" ;
    String data1 = StrUtils.strjoinNL
        ("prefix : <"+ns+">"
        ,":s :p '000-"+x+"' ."
        ,":s :p '111-"+x+"' ."
        ," :g {"
        ,"    :s :p '222-"+x+"' ."
        ,"    :s :p '333-"+x+"' ."
        ,"    :s :p '444-"+x+"' ."
        ,"}"
        ) ;
    String data2 = StrUtils.strjoinNL
        ("prefix : <"+ns+">"
        ,":s :p 'AAA-"+x+"' ."
        ,":s :p 'BBB-"+x+"' ."
        ,":s :p 'CCC-"+x+"' ."
        ,":s :p 'DDD-"+x+"' ."
        ) ;
    
    Dataset dataset ; 
    Location location ;
    
    @Before public void before() {
        location = Location.mem() ;
        dataset = TDB2Factory.connectDataset(location) ;
    }

    @After public void after() {
        dataset.close() ;
        TDBInternal.expel(dataset.asDatasetGraph());
    }

    // Models across transactions
    @Test public void trans_01() {
        Model named = dataset.getNamedModel(ns+"g") ;
        Txn.executeWrite(dataset, ()->{
            RDFDataMgr.read(dataset, new StringReader(data1), null, Lang.TRIG) ;
        }) ;

        Txn.executeRead(dataset, ()->{
            long x1 = Iter.count(dataset.getDefaultModel().listStatements()) ;
            assertEquals(2, x1) ;
            long x2 = Iter.count(named.listStatements()) ;
            assertEquals(3, x2) ;
        }) ;
        
    }
    
    @Test public void trans_02() {
        Model model = dataset.getDefaultModel() ;
        Txn.executeWrite(dataset, ()->{
            RDFDataMgr.read(model, new StringReader(data2), null, Lang.TURTLE) ;
        }) ;
        Txn.executeRead(dataset, ()->{
            assertEquals(4, model.size()) ;
        }) ;        
    }
    
    // Iterators and trasnaxction scope.
    
    private void load(String data) { 
        Txn.executeWrite(dataset, ()->{
            RDFDataMgr.read(dataset, new StringReader(data), null, Lang.TURTLE) ;
        }) ;
    }
    
    public void iterator_01() {
        load(data2);
        
        dataset.begin(ReadWrite.READ);
        Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
        Iter.consume(iter);
        dataset.end();
    }
    
    @Test(expected=TransactionException.class)
    public void iterator_02() {
        load(data2);
        
        dataset.begin(ReadWrite.READ);
        Iterator<Quad> iter = dataset.asDatasetGraph().find();
        dataset.end();
        iter.next();
    }
    
    @Test(expected=TransactionException.class)
    public void iterator_03() {
        load(data2);
        
        dataset.begin(ReadWrite.READ);
        Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
        dataset.end();
        iter.next();
    }

    @Test(expected=TransactionException.class)
    public void iterator_04() {
        load(data2);
        Iterator<Statement> iter = Txn.calculateRead(dataset, ()->dataset.getDefaultModel().listStatements());
        iter.next();
    }
    
    @Test(expected=TransactionException.class)
    public void iterator_05() {
        load(data2);
        Iterator<Statement> iter = Txn.calculateWrite(dataset, ()->dataset.getDefaultModel().listStatements());
        iter.next();
    }

    @Test(expected=TransactionException.class)
    public void iterator_06() {
        load(data2);
        
        dataset.begin(ReadWrite.READ);
        Iterator<Quad> iter = dataset.asDatasetGraph().find();
        dataset.end();
        
        dataset.begin(ReadWrite.READ);
        iter.next();
        dataset.end();
    }
    
//    @Test
//    public void iterator_07() {
//        load(data2);
//        
//        // Isolated by copy.
//        Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
//        
//        dataset.begin(ReadWrite.READ);
//        iter.next();
//        dataset.end();
//    }
//
//    @Test
//    public void iterator_08() {
//        load(data2);
//        
//        // Isolated by copy.
//        Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
//        
//        dataset.begin(ReadWrite.READ);
//        dataset.end();
//        iter.next();
//    }
}


