!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: jstring.gs,v 1.7 2008-01-09 22:50:12 stever Exp $
!
! Superclass Hierarchy:
!   JapaneseString, CharacterCollection, SequenceableCollection, Collection,
!   Object.
!
!=========================================================================

removeallmethods JapaneseString
removeallclassmethods JapaneseString

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

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

txt := (GsDocText new) details:
'This class represents behavior common to all JapaneseString classes.

 Subclasses must reimplement the following selectors:

 #size  #size: #at: #at:put:

 However these selectors do not generate the subclass-responsibility error
 (error 2008) because to do so would break Object | printString method.'.
doc documentClassWith: txt.

self description: doc.
%

! size  size:  at:  at:put:  removed so they can be inherited to make
!   printString bulletproof.  If these selectors were to generate
!  subclass responsibility errors, then new must be disallowed and reimplemented
!  by subclasses also.

category: 'Formatting'
method: JapaneseString
printString

"Returns a String whose contents are a displayable representation of the
 receiver."

| ws str |

str := JISString new.
ws := PrintStream printingOn: str.
self printOn: ws.
^str
%

category: 'Formatting'
method: JapaneseString
printOn: aStream

"Puts a displayable representation of the receiver on the given stream."

"This implementation uses JISString as the unifying collection class for the
 stream.  For literal classes, the result should contain formatting information.
 For example the following expression should evaluate to true:

 #abc asString = String withAll: '#abc'"

| subStr idx lastIdx sz strmClass |

strmClass := aStream _collection class .
((strmClass == EUCString _or:[strmClass == String]) _or:[strmClass == ISOLatin])
  ifTrue:[ aStream _convertToJIS ].

self size > 1000 ifTrue:[
  ^ aStream nextPutAll: self .
  ]. 
aStream nextPut: $' .
idx := self indexOf: $' startingAt: 1 .
idx == 0 ifTrue:[
  aStream nextPutAll: self .
  ]
ifFalse:[
  subStr := JISString new . 
  lastIdx := 1.
  [ idx == 0 ] whileFalse: [
    self copyFrom: lastIdx to: idx into: subStr startingAt: 1 .
    aStream nextPutAll: subStr .
    subStr size: 0 .
    aStream nextPut: $' .
    lastIdx := idx + 1 .
    idx := self indexOf: $' startingAt: lastIdx .
    ].
  sz := self size .
  lastIdx <= sz ifTrue: [
    self copyFrom: lastIdx to: sz into: subStr startingAt: 1 .
    aStream nextPutAll: subStr .
    subStr size: 0 .
    ].
  ].
aStream nextPut: $' 
%

category: 'Converting'
method: JapaneseString
asEUCString

"Returns an EUCString representing the receiver."

"Must be reimplemented in EUCString to return self !!
 This implementation handles other weird kinds of multiple-byte Strings
 that the user or engineers might dream up."

| s |
s := EUCString new .
self do:[ :aChar | s add: aChar asJISCharacter ].
^ s 
%

category: 'Concatenating'
method: JapaneseString
, aCharOrCharCollection

"Returns a new instance of the receiver's class that contains the elements of
 the receiver followed by the elements of aCharOrCharCollection.

 Warning: Creating a new instance and copying the receiver take time.  If you
 can safely modify the receiver, it can be much faster to use the addAll:
 method.  See the documentation of the Concatenating category of class
 SequenceableCollection for more details."

| resultClass jisStrCls |

resultClass := self class  .
aCharOrCharCollection class == (jisStrCls := JISString) ifTrue:[
  resultClass := jisStrCls . 
  ]. 

^ resultClass new add: self;
                  add: aCharOrCharCollection;
                  yourself
%

! fix bug 9447
category: 'Storing and Loading'
method: JapaneseString
loadFrom: passiveObj

"Reads from passiveObj the passive form of an object.  Converts the object to
 its active form by loading the information into the receiver."

passiveObj hasRead: self.
passiveObj next: self _basicSize basicBytesTo: self.
passiveObj next.  "consume the space put after all strings"
^self
%

category: 'Storing and Loading'
method: JapaneseString
writeTo: passiveObj

"Converts the receiver to its passive form and writes that information on
 passiveObj."

| s mySize |

"copy bytes of self into an instance of String, with no translation."
mySize := self _basicSize .
s := String new: mySize .
mySize > 0 ifTrue:[
  self _copyFrom: 1 to: mySize intoString: s startingAt: 1 .
  ].
passiveObj writeClass: self class;
  writeSize: mySize ;
  nextPutAll: s; space .
				"deleted   'reduce garbage' code"
%

category: 'Copying'
method: JapaneseString
_copyFrom: index1 to: index2 intoString: aString startingAt: index3

"Copies the bytes of the receiver between index1 and index2, inclusive, into
 aString starting at index3, overwriting the previous contents.  If aString is
 the same object as the receiver, the source and destination blocks may overlap.
 aString must be a kind of String."

"This uses the primitive for String | _copyFrom:to:intoString:startingAt:
 and is used to implement passivation of JapaneseStrings."

<primitive: 297>

(index1 > index2)
  ifTrue: [ ^ index1 _error: #rtErrBadCopyFromTo args: #[index2]].

(index1 < 1)
  ifTrue: [ ^ self _errorIndexOutOfRange: index1].

(index2 > self size)
  ifTrue: [ ^ self _errorIndexOutOfRange: index2].

((index3 < 1) _or: [(index3 > (aString size + 1))])
  ifTrue: [ ^ aString _errorIndexOutOfRange: index3].

^ self _primitiveFailed: #_copyFrom:to:intoString:startingAt:
%

category: 'Searching'
method: JapaneseString
findString: subString startingAt: startIndex

"If the receiver contains subString beginning at some point at or after
 startIndex, returns the index at which subString begins.  If the receiver does
 not contain subString, returns zero."

"check for errors"
subString _validateClass: CharacterCollection.
(((startIndex < 1) _or: [startIndex > self size]) _or: [self size == 0])
   ifTrue: [ ^ self _errorIndexOutOfRange: startIndex ].

"now find the substring"
(subString size == 0) ifTrue: [^startIndex].
startIndex to: ((self size) - (subString size) + 1) do: [:i |
   (self at: i equals: subString)
   ifTrue: [ ^i ]
].
^0
%

category: 'Removing'
method: JapaneseString
removeFrom: startIndex to: stopIndex

"(R) Deletes the elements of the receiver from startIndex to stopIndex.  The
 size of the receiver is decreased by stopIndex - startIndex + 1.

 Both startIndex and stopIndex must be positive integers not larger than the
 size of the receiver, with startIndex <= stopIndex."

((stopIndex > self size) _or: [(stopIndex < 1)])
   ifTrue: [ ^ self _errorIndexOutOfRange: stopIndex].
stopIndex == self size ifTrue:[
  self size: (startIndex - 1) .
  ^ self
  ].
self copyFrom: stopIndex + 1 to: self size into: self startingAt: startIndex .
self size: self size - (stopIndex - startIndex + 1)
%

category: 'Adding'
method: JapaneseString
insertAll: aCharOrCharColl at: anIndex

"Inserts aCharOrCharColl at the specified index.  Returns aCharOrCharColl."

| argSize origSize |
(anIndex < 1 _or:[ anIndex > (self size + 1)])
   ifTrue: [ ^ self _errorIndexOutOfRange: anIndex].
argSize := aCharOrCharColl size .
anIndex == (self size + 1) ifTrue:[
  self addAll: aCharOrCharColl .
  ^ aCharOrCharColl
  ].
origSize := self size.
self size: origSize + argSize.
self copyFrom: anIndex to: origSize
     into: self startingAt: anIndex + argSize .
aCharOrCharColl copyFrom: 1 to: argSize into: self startingAt: anIndex .
^ aCharOrCharColl
%

! deleted JapaneseString>>_idxCompareEqualTo: in v2.0 (bugfix 34042)
