from history import *
from history.record import *

import os
import unittest
import warnings 

warnings.simplefilter("ignore", Warning)

class TestCommentRecord(unittest.TestCase):

    tag           = "COMMENT "
    empty_content = "                                                                        "
    fits_content  = " ########## Configuration control keywords ##########                   "
    long_content  = " FITS (Flexible Image Transport System) format is defined in 'Astronomy and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H"
    short_content = " ------- Observation Information -------"

    # Standard FITS longkey comment blurb.
    longkey_line  = "This FITS file may contain long string keyword values that are          continued over multiple keywords.  This convention uses the  '&'        character at the end of a string which is then continued                on subsequent keywords whose name = 'CONTINUE'                          "
    longkey_block = ["00000000011111111112222222222333333333344444444445555555555666666666677777777778",
                     "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
                     "COMMENT This FITS file may contain long string keyword values that are          ",
                     "COMMENT continued over multiple keywords.  This convention uses the  '&'        ",
                     "COMMENT character at the end of a string which is then continued                ",
                     "COMMENT on subsequent keywords whose name = 'CONTINUE'                          ",
                     ]

    def test_01(self):
        # Constructor Testing: [a.b.c] == reference to UDF test plan.
        for ii in range(0,3):
            if ii == 0:
                content = self.fits_content
                errmsg  = "[2.1.1] - standard FITS card "
            elif ii == 1:
                content = self.empty_content
                errmsg  = "[2.1.2] - empty content "
            elif ii == 2:
                content = self.long_content
                errmsg  = "[2.1.3] - long content "

            for jj in range(0,2): # with/without tag
                if jj == 0:
                    card = content
                else:
                    card = self.tag + content
                    errmsg = errmsg + "with tag "

                try:
                    c1 = CommentRecord( card )
                except Exception as ex:
                    print(ex)
                    raise Exception( errmsg +": FAILED")

                # Check content interpretation
                self.assertEqual( c1._content, content )

        # Default
        errmsg = "[2.1.4] - default "
        try:
            c1 = CommentRecord()
        except Exception as ex:
            print(ex)
            raise Exception( errmsg +": FAILED")
        self.assertEqual( c1._content, "" )


        # Construct BLANK record
        try:
            errmsg = "[2.1.5] - BLANK "
            c1 = CommentRecord( is_blank=True )
        except Exception as ex:
            print(ex)
            raise Exception( errmsg +": FAILED")
        self.assertEqual( c1._content, "" )

        # Construct BLANK record with content
        try:
            errmsg = "[2.1.6] - BLANK with content"
            c1 = CommentRecord( self.fits_content, is_blank=True )
        except ValueError as ve:
            # check error message?
            pass
        except Exception as ex:
            print( ex.__class__.__name__ + ": " + str(ex))
            raise Exception("Error: expected exception not thrown")
        else:
            raise Exception("Error: No exception thrown for bad input.")

        # Construct with non-string content (numeric)
        try:
            errmsg = "[2.1.7] - non string content "
            c1 = CommentRecord( 666 )
        except TypeError as ve:
            # check error message?
            pass
        except Exception as ex:
            print( ex.__class__.__name__ + ": " + str(ex))
            raise Exception("Error: expected exception not thrown")
        else:
            raise Exception("Error: No exception thrown for bad input.")

        # Construct with non-string content (list)
        try:
            errmsg = "[2.1.7] - non string content "
            c1 = CommentRecord( [ self.fits_content ] )
        except TypeError as ve:
            # check error message?
            pass
        except Exception as ex:
            print( ex.__class__.__name__ + ": " + str(ex))
            raise Exception("Error: expected exception not thrown")
        else:
            raise Exception("Error: No exception thrown for bad input.")


    def test_02(self):
        # check that CommentRecord is a subclass and instance of Record
        if issubclass(CommentRecord, Record) is not True:
           raise Exception("issubclass FAILED")
        if isinstance(CommentRecord(), Record) is not True:
           raise Exception("isinstance FAILED")
        if isinstance(CommentRecord(), CommentRecord) is not True:
           raise Exception("isinstance FAILED")


    def test_03(self):
        # Test class property access (content and afterkey)

        content = self.fits_content
        keyname = "OBS_ID"
      
        c1 = CommentRecord(content)     

        # [2.2.3] read content from public property
        try:
            result = c1.content
        except Exception as ex:
            print(ex)
            raise Exception( "[2.2.3] read content: FAILED")
        self.assertEqual( result, content )
        
        # [2.2.1] set content via public property
        try:
            c1.content = self.empty_content
        except AttributeError as ve:
            # check error message?
            pass
        except Exception as ex:
            print( ex.__class__.__name__ + ": " + str(ex))
            raise Exception("Error: expected exception not thrown")
        else:
            raise Exception("Error: No exception thrown for bad input.")

        # [2.2.2] set content via protected property
        try:
            c1._content = self.empty_content
        except Exception as ex:
            print(ex)
            raise Exception( "[2.2.2] re-set content: FAILED")
        result = c1.content
        self.assertEqual( result, self.empty_content )

        # [2.2.1] set afterkey via public property
        try:
            c1.afterkey = keyname
        except AttributeError as ve:
            # check error message?
            pass
        except Exception as ex:
            print( ex.__class__.__name__ + ": " + str(ex))
            raise Exception("Error: expected exception not thrown")
        else:
            raise Exception("Error: No exception thrown for bad input.")

        # [2.2.2] set afterkey via protected property
        try:
            c1._afterkey = keyname
        except Exception as ex:
            print(ex)
            raise Exception( "[2.2.3] read content: FAILED")

        # [2.2.3] read afterkey from public property
        result = c1.afterkey
        self.assertEqual( result, keyname )

        # read afterkey from protected property
        result = c1._afterkey
        self.assertEqual( result, keyname )


    def test_03(self):
        # Test special content cases
        #    COMMENT and HISTORY are special words in this class..
        #    verify that use of them within content is not a problem.

        text1  = "USER COMMENT SECTION"
        text2  = "----  PROCESSING HISTORY ----"

        try:
            c1 = CommentRecord( text1 )
        except Exception as ex:
            print(ex)
            raise Exception( "[2.3.1] read content with COMMENT in text: FAILED")
        self.assertEqual( c1._content, text1 )

        try:
            c1 = CommentRecord( self.tag + text1 )
        except Exception as ex:
            print(ex)
            raise Exception( "[2.3.1] read content with COMMENT in text: FAILED")
        self.assertEqual( c1._content, text1 )

        try:
            c1 = CommentRecord( text2 )
        except Exception as ex:
            print(ex)
            raise Exception( "[2.3.2] read content with HISTORY in text: FAILED")
        self.assertEqual( c1._content, text2 )

        try:
            c1 = CommentRecord( self.tag + text2 )
        except Exception as ex:
            print(ex)
            raise Exception( "[2.3.2] read content with HISTORY in text: FAILED")
        self.assertEqual( c1._content, text2 )


    def test_04(self):
        # Test represenations - FITS content [2.4.*]

        content   = self.fits_content
        expectedA = "Content:    '"+content+"'\n"
        expectedB = content
        expectedC = self.tag + content

        c1 = CommentRecord( content )

        # __str__()
        result = str( c1 )
        self.assertEqual( result, expectedA )

        # as_string( with_tag=False )
        result = c1.as_string( with_tag=False )
        self.assertEqual( result, expectedB )

        # as_string( with_tag=True )
        result = c1.as_string( with_tag=True )
        self.assertEqual( result, expectedC )

        # as_FITS( with_tag=False )
        result = c1.as_FITS( with_tag=False )
        self.assertEqual( result, expectedB )

        # as_FITS( with_tag=True )
        result = c1.as_FITS( with_tag=True )
        self.assertEqual( result, expectedC )

    def test_05(self):
        # Test represenations - Empty content [2.5.*]

        content   = ""
        expectedA = "Content:    '"+content+"'\n"
        expectedB = content
        expectedC = self.tag + content
        expectedD = self.empty_content
        expectedE = self.tag + self.empty_content

        c1 = CommentRecord( content )

        # __str__()
        result = str( c1 )
        self.assertEqual( result, expectedA )

        # as_string( with_tag=False )
        result = c1.as_string( with_tag=False )
        self.assertEqual( result, expectedB )

        # as_string( with_tag=True )
        result = c1.as_string( with_tag=True )
        self.assertEqual( result, expectedC )

        # as_FITS( with_tag=False )
        result = c1.as_FITS( with_tag=False )
        self.assertEqual( result, expectedD )

        # as_FITS( with_tag=True )
        result = c1.as_FITS( with_tag=True )
        self.assertEqual( result, expectedE )
        self.assertEqual( len(result), 80 )

    def test_06(self):
        # Test represenations - short content (< 80 chars) [2.6.*]

        content   = self.short_content
        expectedA = "Content:    '"+content+"'\n"
        expectedB = content
        expectedC = self.tag + content
        expectedD = '{:72}'.format(content)
        expectedE = self.tag + expectedD

        c1 = CommentRecord( content )

        # __str__()
        result = str( c1 )
        self.assertEqual( result, expectedA )

        # as_string( with_tag=False )
        result = c1.as_string( with_tag=False )
        self.assertEqual( result, expectedB )

        # as_string( with_tag=True )
        result = c1.as_string( with_tag=True )
        self.assertEqual( result, expectedC )

        # as_FITS( with_tag=False )
        result = c1.as_FITS( with_tag=False )
        self.assertEqual( result, expectedD )

        # as_FITS( with_tag=True )
        result = c1.as_FITS( with_tag=True )
        self.assertEqual( result, expectedE )
        self.assertEqual( len(result), 80 )

    def test_07(self):
        # Test represenations - long content (> 80 chars) [2.7.*]

        content   = self.long_content
        expectedA = "Content:    '"+content+"'\n"
        expectedB = content
        expectedC = self.tag + content
        expectedD = " FITS (Flexible Image Transport System) format is defined in 'Astronomy \nand Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H   "

        c1 = CommentRecord( content )

        # __str__()
        result = str( c1 )
        self.assertEqual( result, expectedA )

        # as_string( with_tag=False )
        result = c1.as_string( with_tag=False )
        self.assertEqual( result, expectedB )

        # as_string( with_tag=True )
        result = c1.as_string( with_tag=True )
        self.assertEqual( result, expectedC )

        # as_FITS( with_tag=False )
        result = c1.as_FITS( with_tag=False )
        self.assertEqual( result, expectedD )

        # as_FITS( with_tag=True )
        result = c1.as_FITS( with_tag=True )
        rparts = result.splitlines()
        eparts = expectedD.splitlines()
        for ii in range(0,len(eparts)):
            self.assertEqual( rparts[ii], self.tag + eparts[ii] )
            self.assertEqual( len(rparts[ii]), 80 )

        # This chunk will verifies the wrapping and card lengh.
        # Make a record of standard FITS long keyword convention comment block
        c2 = CommentRecord( self.longkey_line )

        # String representation should be unchanged
        result = c2.as_string()
        self.assertEqual( result, self.longkey_line )

        # Extract FITS string representation
        result = c2.as_FITS( with_tag=True )

        # Compare with stored FITS cards
        expected = "\n".join(self.longkey_block[2:])
        self.assertEqual( result, expected )


    def test_08(self):
        # Test represenations - BLANK record [2.8.*]

        expectedA = "Content:    <Completely BLANK Line>\n"
        expectedB = ""
        expectedC = ""
        expectedD = '{:72}'.format(" ")
        expectedE = '{:80}'.format(" ")

        c1 = CommentRecord( is_blank=True )

        # __str__()
        result = str( c1 )
        self.assertEqual( result, expectedA )

        # as_string( with_tag=False )
        result = c1.as_string( with_tag=False )
        self.assertEqual( result, expectedB )

        # as_string( with_tag=True )
        result = c1.as_string( with_tag=True )
        self.assertEqual( result, expectedC )

        # as_FITS( with_tag=False )
        result = c1.as_FITS( with_tag=False )
        self.assertEqual( result, expectedD )

        # as_FITS( with_tag=True )
        result = c1.as_FITS( with_tag=True )
        self.assertEqual( result, expectedE )


if __name__ == '__main__':
    unittest.main(verbosity=5)
