/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  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.  For additional information regarding
 * copyright in this work, please see the NOTICE file in the top level
 * directory of this distribution.
 */

package org.apache.roller.weblogger.business;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.weblogger.TestUtils;
import org.apache.roller.weblogger.WebloggerException;
import org.apache.roller.weblogger.pojos.*;
import org.apache.roller.weblogger.pojos.WeblogEntryComment.ApprovalStatus;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Test Comment related business operations.
 *
 * That includes:
 */
public class CommentTest  {
    
    public static Log log = LogFactory.getLog(CommentTest.class);
    
    User testUser = null;
    Weblog testWeblog = null;
    WeblogEntry testEntry = null;
    

    /**
     * All tests in this suite require a user, weblog, and an entry.
     */
    @BeforeEach
    public void setUp() throws Exception {
        
        // setup weblogger
        TestUtils.setupWeblogger();
        
        try {
            testUser = TestUtils.setupUser("commentTestUser");
            testWeblog = TestUtils.setupWeblog("commentTestWeblog", testUser);
            testEntry = TestUtils.setupWeblogEntry("commentTestEntry", testWeblog, testUser);
            TestUtils.endSession(true);
        } catch (Exception ex) {
            log.error(ex);
            throw new Exception("Test setup failed", ex);
        }
    }

    @AfterEach
    public void tearDown() throws Exception {
        
        try {
            TestUtils.teardownWeblogEntry(testEntry.getId());
            TestUtils.teardownWeblog(testWeblog.getId());
            TestUtils.teardownUser(testUser.getUserName());
            TestUtils.endSession(true);
        } catch (Exception ex) {
            log.error(ex);
            throw new Exception("Test teardown failed", ex);
        }
    }
    
    
    /**
     * Test basic persistence operations ... Create, Update, Delete
     */
    public void testCommentCRUD() throws Exception {
        
        WeblogEntryManager mgr = WebloggerFactory.getWeblogger().getWeblogEntryManager();
        
        WeblogEntryComment comment = new WeblogEntryComment();
        comment.setName("test");
        comment.setEmail("test");
        comment.setUrl("test");
        comment.setRemoteHost("foofoo");
        comment.setContent("this is a test comment");
        comment.setPostTime(new java.sql.Timestamp(new java.util.Date().getTime()));
        comment.setWeblogEntry(TestUtils.getManagedWeblogEntry(testEntry));
        comment.setStatus(ApprovalStatus.APPROVED);
        
        // create a comment
        mgr.saveComment(comment);
        String id = comment.getId();
        TestUtils.endSession(true);
        
        // make sure comment was created
        comment = mgr.getComment(id);
        assertNotNull(comment);
        assertEquals("this is a test comment", comment.getContent());
        
        // update a comment
        comment.setContent("testtest");
        mgr.saveComment(comment);
        TestUtils.endSession(true);
        
        // make sure comment was updated
        comment = mgr.getComment(id);
        assertNotNull(comment);
        assertEquals("testtest", comment.getContent());
        
        // delete a comment
        mgr.removeComment(comment);
        TestUtils.endSession(true);
        
        // make sure comment was deleted
        comment = mgr.getComment(id);
        assertNull(comment);
    }
    
    
    /**
     * Test lookup mechanisms ... 
     */
    public void testCommentLookups() throws Exception {
        
        WeblogEntryManager mgr = WebloggerFactory.getWeblogger().getWeblogEntryManager();
        List<WeblogEntryComment> comments;
        
        // we need some comments to play with
        testEntry = TestUtils.getManagedWeblogEntry(testEntry);
        WeblogEntryComment comment1 = TestUtils.setupComment("comment1", testEntry);
        WeblogEntryComment comment2 = TestUtils.setupComment("comment2", testEntry);
        WeblogEntryComment comment3 = TestUtils.setupComment("comment3", testEntry);
        TestUtils.endSession(true);
        
        // get all comments
        CommentSearchCriteria csc = new CommentSearchCriteria();
        comments = mgr.getComments(csc);
        assertNotNull(comments);
        assertEquals(3, comments.size());
        
        // get all comments for entry
        testEntry = TestUtils.getManagedWeblogEntry(testEntry);
        csc.setEntry(testEntry);
        comments = mgr.getComments(csc);
        assertNotNull(comments);
        assertEquals(3, comments.size());
        
        // make some changes
        comment3 = mgr.getComment(comment3.getId());
        comment3.setStatus(ApprovalStatus.PENDING);
        mgr.saveComment(comment3);
        TestUtils.endSession(true);
        
        // get pending comments
        csc.setEntry(null);
        csc.setStatus(ApprovalStatus.PENDING);
        comments = mgr.getComments(csc);
        assertNotNull(comments);
        assertEquals(1, comments.size());
        
        // get approved comments
        csc.setStatus(ApprovalStatus.APPROVED);
        comments = mgr.getComments(csc);
        assertNotNull(comments);
        assertEquals(2, comments.size());
        
        // get comments with offset
        csc.setStatus(null);
        csc.setOffset(1);
        comments = mgr.getComments(csc);
        assertNotNull(comments);
        assertEquals(2, comments.size());
        
        // remove test comments
        TestUtils.teardownComment(comment1.getId());
        TestUtils.teardownComment(comment2.getId());
        TestUtils.teardownComment(comment3.getId());
        TestUtils.endSession(true);
    }
    
    
    /**
     * Test that when deleting parent objects of a comment that everything
     * down the chain is properly deleted as well.  i.e. deleting an entry
     * should delete all comments on that entry, and deleting a weblog should
     * delete all comments, etc.
     */
    public void testCommentParentDeletes() throws Exception {
        
        log.info("BEGIN");
        
        try {
            WeblogManager wmgr = WebloggerFactory.getWeblogger().getWeblogManager();        
            WeblogEntryManager emgr = WebloggerFactory.getWeblogger().getWeblogEntryManager();        
            UserManager umgr = WebloggerFactory.getWeblogger().getUserManager();

            // first make sure we can delete an entry with comments
            User user = TestUtils.setupUser("commentParentDeleteUser");
            Weblog weblog = TestUtils.setupWeblog("commentParentDelete", user);
            WeblogEntry entry = TestUtils.setupWeblogEntry("CommentParentDeletes1", weblog, user);
            TestUtils.endSession(true);

            entry = TestUtils.getManagedWeblogEntry(entry);
            TestUtils.setupComment("comment1", entry);
            TestUtils.setupComment("comment2", entry);
            TestUtils.setupComment("comment3", entry);
            TestUtils.endSession(true);

            // now deleting the entry should succeed and delete all comments
            Exception ex = null;
            try {
                emgr.removeWeblogEntry(TestUtils.getManagedWeblogEntry(entry));
                TestUtils.endSession(true);
            } catch (WebloggerException e) {
                ex = e;
            }
            assertNull(ex);

            // now make sure we can delete a weblog with comments
            weblog = TestUtils.getManagedWebsite(weblog);
            user = TestUtils.getManagedUser(user);
            entry = TestUtils.setupWeblogEntry("CommentParentDeletes2", weblog, user);
            TestUtils.endSession(true);

            entry = TestUtils.getManagedWeblogEntry(entry);
            TestUtils.setupComment("comment1", entry);
            TestUtils.setupComment("comment2", entry);
            TestUtils.setupComment("comment3", entry);
            TestUtils.endSession(true);

            // now deleting the website should succeed 
            ex = null;
            try {
                weblog = TestUtils.getManagedWebsite(weblog);
                wmgr.removeWeblog(weblog);
                TestUtils.endSession(true);
            } catch (WebloggerException e) {
                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw); 
                e.printStackTrace(pw);
                log.info(sw.toString());
                ex = e;
            }
            assertNull(ex);

            // and delete test user as well
            umgr.removeUser(TestUtils.getManagedUser(user));
            
        } finally {
            TestUtils.endSession(true);
        }
        
        log.info("END");
    }
    
    
    /**
     * Apparently, HSQL has "issues" with LIKE expressions, 
     * so I'm commenting this out for now. 
     
    public void _testBulkCommentDelete() throws Exception {
        
        WeblogManager mgr = RollerFactory.getRoller().getWeblogManager();
        List comments = null;
        
        // we need some comments to play with
        WeblogEntryComment comment1 = TestUtils.setupComment("deletemeXXX", testEntry);
        WeblogEntryComment comment2 = TestUtils.setupComment("XXXdeleteme", testEntry);
        WeblogEntryComment comment3 = TestUtils.setupComment("deleteme", testEntry);
        WeblogEntryComment comment4 = TestUtils.setupComment("saveme", testEntry);
        WeblogEntryComment comment5 = TestUtils.setupComment("saveme", testEntry);
        WeblogEntryComment comment6 = TestUtils.setupComment("saveme", testEntry);
        TestUtils.endSession(true);
        
        // get all comments
        comments = null;
        comments = mgr.getComments(
            null, // website
            null, // entry
            null, // searchString
            null, // startDate
            null, // endDate
            null, // pending
            null, // approved
            null, // spam
            true, // reverseChrono
             0,   // offset
            -1);  // length
        assertNotNull(comments);
        assertEquals(6, comments.size());
        
        comments = mgr.getComments(
            null, // website
            null, // entry
            "deleteme", // searchString
            null, // startDate
            null, // endDate
            null, // pending
            null, // approved
            null, // spam
            true, // reverseChrono
             0,   // offset
            -1);  // length
        assertNotNull(comments);
        assertEquals(3, comments.size());
       
        int countDeleted = mgr.removeMatchingComments(
            null,         // website
            null,         // entry
            "deleteme",  // searchString
            null,         // startDate
            null,         // endDate
            null,         // pending
            null,         // approved
            null);        // spam        
        assertEquals(3, countDeleted);
        
        comments = mgr.getComments(
            null, // website
            null, // entry
            null, // searchString
            null, // startDate
            null, // endDate
            null, // pending
            null, // approved
            null, // spam
            true, // reverseChrono
             0,   // offset
            -1);  // length
        assertNotNull(comments);
        assertEquals(3, comments.size());
        
        // remove test comments
        countDeleted = mgr.removeMatchingComments(
            null,         // website
            null,         // entry
            "saveme",    // searchString
            null,         // startDate
            null,         // endDate
            null,         // pending
            null,         // approved
            null);        // spam        
        assertEquals(3, countDeleted);
        TestUtils.endSession(true);
    }
    */
    
    /**
     * Test extra CRUD methods ... removeComments(ids), removeCommentsForEntry
     */
//    public void testAdvancedCommentCRUD() throws Exception {
//        
//        WeblogManager mgr = WebloggerFactory.getWeblogger().getWeblogManager();
//        List comments = null;
//        
//        // we need some comments to play with
//        WeblogEntryComment comment1 = TestUtils.setupComment("comment1", testEntry);
//        WeblogEntryComment comment2 = TestUtils.setupComment("comment2", testEntry);
//        WeblogEntryComment comment3 = TestUtils.setupComment("comment3", testEntry);
//        WeblogEntryComment comment4 = TestUtils.setupComment("comment4", testEntry);
//        TestUtils.endSession(true);
//        
//        // remove a collection of comments
//        String[] delComments = new String[2];
//        delComments[0] = comment1.getId();
//        delComments[1] = comment2.getId();
//        mgr.removeComments(delComments);
//        TestUtils.endSession(true);
//        
//        // make sure comments were deleted
//        comments = null;
//        comments = mgr.getComments(null, null, null, null, null, null, null, null, false, 0, -1);
//        assertNotNull(comments);
//        assertEquals(2, comments.size());
//        
//        // remove all comments for entry
//        mgr.removeCommentsForEntry(testEntry.getId());
//        TestUtils.endSession(true);
//        
//        // make sure comments were deleted
//        comments = null;
//        comments = mgr.getComments(null, null, null, null, null, null, null, null, false, 0, -1);
//        assertNotNull(comments);
//        assertEquals(0, comments.size());
//    }
    
}
