!=========================================================================
! Copyright (C) VMware, Inc. 1991-2011.  All Rights Reserved
!
! $Id: printstream.gs,v 1.5 2008-01-09 22:50:13 stever Exp $
!
!=========================================================================

! Create the class PrintStream, if it does not already exist

! can't use _newKernelSubclass: because that uses Class>>definition,
!   which uses printString ...

expectvalue %String
run
^  Stream _newKernelSubclass: 'PrintStream'
    instVarNames: #( 'itsCollection' 'maxSize' 'approxPosition' )
    classVars: #()
    classInstVars: #()
    poolDictionaries: #[]
    inDictionary: Globals
    constraints: #[ #[ #itsCollection, SequenceableCollection ] ]
		    "approxPosition and maxSize should be Integers"
    instancesInvariant: false
    isModifiable: false
    reservedOop: 845 .  
%

!========================================================================
! remove all methods

removeallmethods PrintStream
removeallclassmethods PrintStream

category: 'For Documentation Installation only'
classmethod: PrintStream
installDocumentation

| doc txt |
doc := GsClassDocumentation _newForPrivateGsClass: self.

txt := (GsDocText new) details:
'PrintStream is designed for use in place of WriteStream to handle printing
 of mixed ASCII and JapaneseStrings.  The default size of the stream is limited
 to 100000 bytes.'.
doc documentClassWith: txt.

self description: doc.
%

category: 'Adding'
method: PrintStream
nextPut: anObject

"Inserts anObject as the next element that the receiver can access for writing.
 Returns anObject."

itsCollection addLast: anObject .
approxPosition := approxPosition + 1 .
^ anObject
%

category: 'Adding'
method: PrintStream
nextPutAll: aCollection

"Inserts the elements of aCollection as the next elements that the receiver can
 access.  Returns aCollection."

| newPosition sz |

"Check to prevent receiver from growing to ridiculous size if we are printing
 a collection of large strings ...  Don't track logical size of EUCStrings
 accurately because it's too expensive.
"
sz := aCollection _basicSize .
newPosition := approxPosition + sz .
newPosition < maxSize ifTrue:[ 
  itsCollection addAll: aCollection .
  approxPosition := newPosition
  ]
ifFalse:[ 
  (aCollection isKindOf: CharacterCollection) ifTrue:[ | prefix lim |
    lim := sz min: 40 .
    prefix := aCollection copyFrom:1 to: lim .
    itsCollection addAll: prefix ; addAll:' ...' .
  ] ifFalse:[ | clsName |
    clsName := aCollection class name 
    itsCollection addAll: '... a large ' ; addAll: clsName; addAll:' ...' .
  ].
  approxPosition := itsCollection size .
] .
^ aCollection
%

category: 'Positioning'
method: PrintStream
_initStreamWith: aCollection maxSize: aMaxSize

"Initializes the receiver's 'itsCollection' instance variable to be
 aCollection."

itsCollection := aCollection.
maxSize := aMaxSize .
approxPosition := 0 .
%

category: 'Instance Creation'
classmethod: PrintStream
on: aCollection

"Returns an instance of the receiver that can stream over the elements of
 aCollection.  The maximum size of the receiver is set to 536870911."

| newStream |

newStream := self _basicNew.
newStream _initStreamWith: aCollection maxSize: 536870911 .
^ newStream
%

category: 'Instance Creation'
classmethod: PrintStream
printingOn: aCollection

"Returns an instance of the receiver that can stream over the elements of
 aCollection. The maximum size of the receiver is set to 100000."

| newStream |

newStream := self _basicNew.
newStream _initStreamWith: aCollection maxSize: 100000 .
^ newStream
%

category: 'Accessing'
method: PrintStream
contents

"Returns the Collection associated with the receiver (that is,
 the sequence of objects that the receiver may access)."

^ itsCollection
%

category: 'Accessing'
method: PrintStream
_collection

"Returns the collection of the receiver."

^itsCollection
%

category: 'Testing'
method: PrintStream
isEmpty

"Returns true if the collection that the receiver accesses contains
 no elements; otherwise returns false."

^ itsCollection size == 0
%

category: 'Converting'
method: PrintStream
_convertToISOLatin

"Converts the receiver's collection from String to ISOLatin.
 Has no effect if the receiver's collection is already an ISOLatin, or
 if the receiver's collection is something other than a String, such as
 a GsFile or a JISString."

| oldStr |

itsCollection class == String ifTrue:[
  oldStr := itsCollection .
  itsCollection := ISOLatin withAll: oldStr  .
  oldStr size: 0 .
  ]
%

category: 'Converting'
method: PrintStream
_convertToEUC

"Converts the receiver's collection from String to EUCString.
 Has no effect if the receiver's collection is already an EUCString, or
 if the receiver's collection is something other than a String, such as
 a GsFile or a JISString."

| oldStr oldCls |

oldStr := itsCollection .
oldCls := itsCollection class .
(oldCls == String _or:[oldCls == ISOLatin]) ifTrue:[ 
  itsCollection := oldStr asEUCString .
  oldStr size: 0 .
  ]
%

category: 'Converting'
method: PrintStream
_convertToJIS

"Converts the receiver's collection to a JISString.
 Has no effect if the receiver's collection is already an JISString, or
 if the receiver's collection is something other than a String or an
 EUCString, such as a GsFile."

| oldStr oldCls |

oldStr := itsCollection .
oldCls := oldStr class .
((oldCls == String _or:[oldCls == EUCString]) _or:[oldCls == ISOLatin]) ifTrue:[ 
  itsCollection := oldStr asJISString .
  oldStr size: 0 .
  ]
%

category: 'Positioning'
method: PrintStream
position

"Returns the receiver's approximate position reference for accessing the 
 sequence of objects. "

^ itsCollection _basicSize
%

