/*
* Lisans bilgisi icin lutfen proje ana dizinindeki zemberek2-lisans.txt dosyasini okuyunuz.
*/
/*
* Created on 24.Eki.2004
*/
package net.zemberek.bilgi.kokler;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import net.zemberek.yapi.Kok;
/**
* Kök düğümü sınıfı Kök ağacının yapıtaşıdır. Her düğüm, kökler, eşseli kökler,
* değişmiş halleri ifade eden bir string ve uygun şekilde bellek kullanımı için
* hazırlanmış özel bir alt düğüm listesi nesnesi taşır.
*
* Çeşitli nedenlerle değişikliğe uğrayabilecek olan kökler ağaca eklenirken
* değişmiş halleri ile beraber eklenirler. Örneğin kitap kökü hem kitab hem de
* kitap hali ile sözlüğe eklenir, ancak bu iki kelime için oluşan düğüm de
* aynı kökü gösterirler. Böylece "kitabına" gibi kelimeler için kök adayları
* aranırken "kitap" köküne erişilmiş olur.
*
* Eş sesli olan kökler aynı düğüme bağlanırlar. Ağacın oluşumu sırasında ilk
* gelen kök düğümdeki kök değişkenine, sonradan gelenler de esSesliler listesine
* eklenirler. Arama sırasında bu kök te aday olarak döndürülür.
*
* @author MDA
*/
public class KokDugumu {
private AltDugumListesi altDugumler = null;
// Her düğüm bir harfle ifade edilir.
private char harf;
// eş seslileri taşıyan liste (Kok nesneleri taşır)
private List esSesliler = null;
// Düğümğn taşıdığı kök
private Kok kok = null;
// Kökün değişmiş halini tutan string
private CharSequence kelime = null;
public KokDugumu() {
}
public KokDugumu(char harf) {
this.harf = harf;
}
public KokDugumu(char harf, CharSequence icerik, Kok kok) {
this.harf = harf;
this.kok = kok;
if (!icerik.equals(kok.icerik())) this.kelime = icerik;
}
/**
* Verilen karakteri taşıyan alt düğümü getirir.
*
* @param in
* @return Eğer verilen karakteri taşıyan bir alt düğüm varsa
* o düğümü, yoksa null.
*/
public final KokDugumu altDugumBul(char in) {
if (altDugumler == null)
return null;
else
return altDugumler.altDugum(in);
}
/**
* Verilen düğümü bu düğüme alt düğüm olarak ekler.
* Dönüş değeri eklenen düğümdür
*
* @param dugum
* @return Eklenen düğüm
*/
public final KokDugumu dugumEkle(KokDugumu dugum) {
if (altDugumler == null) {
altDugumler = new AltDugumListesi();
}
altDugumler.ekle(dugum);
return dugum;
}
/**
* @return tum alt dugumler. dizi olarak.
*/
public final KokDugumu[] altDugumDizisi() {
if (altDugumler == null) {
return new KokDugumu[0];
}
return altDugumler.altDugumlerDizisi();
}
public final boolean altDugumVarMi(){
return !(altDugumler == null || altDugumler.size() == 0);
}
/**
* Eğer Düğüme bağlı bir kök zaten varsa esSesli olarak ekle,
* yoksa sadece kok'e yaz.
*
* @param kok
*/
public final void kokEkle(Kok kok) {
if (this.kok != null) {
if (esSesliler == null) esSesliler = new ArrayList(1);
esSesliler.add(kok);
} else {
this.kok = kok;
}
}
public final Kok kok() {
return this.kok;
}
public final List esSesliler() {
return esSesliler;
}
public final CharSequence kelime() {
if (kelime != null) return kelime;
if (kok != null) return kok.icerik();
return null;
}
public final void setKelime(CharSequence kelime) {
this.kelime = kelime;
}
/**
* @return düğüme bağlı kök ve eş seslilerin hepsini bir listeye
* koyarak geri döndürür.
*/
public List tumKokler() {
if (kok != null) {
ArrayList kokler = new ArrayList();
kokler.add(kok);
if (esSesliler != null) {
kokler.addAll(esSesliler);
}
return kokler;
}
return null;
}
/**
* @return düğüme bağlı tum köklerin icerigi "icerik" ile ayni olanlairni dondurur
* koyarak geri döndürür.
*/
public List tumKokler(String icerik) {
if (kok != null) {
ArrayList kokler = new ArrayList(2);
//if(kok.icerik().equals(icerik))
kokler.add(kok);
if (esSesliler != null) {
kokler.addAll(esSesliler);
// for (Kok esKok : esSesliler) {
// if(esKok.icerik().equals(icerik))
// kokler.add(esKok);
// }
}
return kokler;
}
return null;
}
/**
* Verilen collectiona düğüme bağlı tüm kökleri ekler.
*
* @param kokler
*/
public final void tumKokleriEkle(List kokler) {
if (kok != null && !kokler.contains(kok)) {
kokler.add(kok);
if (esSesliler != null) {
kokler.addAll(esSesliler);
}
}
}
public final void temizle() {
this.kok = null;
this.kelime = null;
this.esSesliler = null;
}
public final void kopyala(KokDugumu kaynak) {
this.kok = kaynak.kok();
this.kelime = kaynak.kelime();
this.esSesliler = kaynak.esSesliler();
}
public final char harf() {
return harf;
}
public final void setHarf(char harf) {
this.harf = harf;
}
/**
* Düğümün ve alt düğümlerinin ağaç yapısı şeklinde string gösterimini döndürür.
* sadece debug amaçlıdır.
*
* @param level
* @return dugumun string halini dondurur.
*/
public final String goster(int level) {
char[] indentChars = new char[level * 2];
for (int i = 0; i < indentChars.length; i++)
indentChars[i] = ' ';
String indent = new String(indentChars);
String str = indent + " Harf: " + harf;
if (kelime != null) {
str += " [Kelime: " + kelime + "] ";
}
if (kok != null) {
str += " [Kok: " + kok + "] ";
}
if (esSesliler != null) {
str += " [Es sesli: ";
for (Kok anEsSesliler : esSesliler) {
str += (anEsSesliler) + " ";
}
str += " ]";
}
KokDugumu[] subNodes = altDugumDizisi();
if (subNodes != null) {
str += "\n " + indent + " Alt dugumler:\n";
for (KokDugumu subNode : subNodes) {
if (subNode != null) {
str += subNode.goster(level + 1) + "\n";
}
}
}
return str;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("harf:").append(harf);
if(altDugumler != null)
buf.append(" alt dugum sayisi:").append(altDugumler.size());
return buf.toString();
}
/**
* Kök agacindaki düğümlerin alt düğümleri için bu sinifi kullanirlar.
* Özellikle bellek kullaniminin önemli oldugu Zemberek-Pardus ve OOo
* eklentisi gibi uygulamalarda bu yapinin kullanilmasi bellek kazanci
* getirmektedir.
* Asagidaki sinifta alt dugum sayisi CEP_BUYUKLUGU degerinden
* az ise sadece CEP_BUYUKLUGU elemanli bir dizi acar. Bu dizi üzerinde
* Arama yapmak biraz daha yavas olsa da ortalama CEP_BUYUKLUGU/2 aramada
* sonuca erişildiği için verilen ceza minimumda kalir.
*
*/
private static final int CEP_BUYUKLUGU = 3;
private final class AltDugumListesi {
KokDugumu[] dugumler = new KokDugumu[CEP_BUYUKLUGU];
int index = 0;
HashMap tumDugumler = null;
/**
* Verilen düğümü alt düğüm olarak ekler. eger alt düğümlerinin sayisi
* CEP_BUYUKLUGU degerini asmissa bir HashMap oluşturur
* @param dugum
*/
public final void ekle(KokDugumu dugum) {
if (index == CEP_BUYUKLUGU) {
if (tumDugumler == null) {
tumDugumler = new HashMap(CEP_BUYUKLUGU + 2);
for (int i = 0; i < CEP_BUYUKLUGU; i++) {
tumDugumler.put(dugumler[i].harf(), dugumler[i]);
}
dugumler = null;
}
tumDugumler.put(dugum.harf(), dugum);
} else {
dugumler[index++] = dugum;
}
}
/**
* Verilen karaktere sahip alt düğümü döndürür.
* @param giris
* @return ilgili KokDugumu
*/
public final KokDugumu altDugum(char giris) {
if (dugumler != null) {
for (int i=0 ; i< index; i++) {
if (dugumler[i].harf() == giris) {
return dugumler[i];
}
}
return null;
} else {
return tumDugumler.get(giris);
}
}
/**
* Alt düğümleri dizi olarak döndürür.
* @return KokDugumu[] cinsinden alt düğümler dizisi
*/
public final KokDugumu[] altDugumlerDizisi() {
if (dugumler != null){
return dugumler;
}
else{
return tumDugumler.values().toArray(new KokDugumu[tumDugumler.values().size()]);
}
}
public final int size(){
if (dugumler != null){
return index;
} else {
return tumDugumler.size();
}
}
}
}