package jsyntaxpane;

import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.text.Segment;
import javax.swing.text.TabExpander;
import javax.swing.text.Utilities;
import javax.swing.text.View;

/**
 *
 * @author JPEXS
 */
public class UniTools {
    
    private static List<String> backupFonts =new ArrayList<String>();
    
    private static boolean fontExists(String name){
        GraphicsEnvironment g=GraphicsEnvironment.getLocalGraphicsEnvironment();
        List<String> availFonts=Arrays.asList(g.getAvailableFontFamilyNames());
        for(int i=0;i<availFonts.size();i++){
            availFonts.set(i, availFonts.get(i).toLowerCase());
        }
        return availFonts.contains(name.toLowerCase());
    }
    
   
    private static String backupCandidates[] = new String[]{"Unifont","Arial Unicode MS"};
    
    
    private static Font defaultUniFont=null;
    static {
        for(String bc:backupCandidates){
            if(fontExists(bc)){
                defaultUniFont = new Font(bc,Font.PLAIN,10);                
            }
        }
        if(defaultUniFont==null){
            defaultUniFont = new JLabel().getFont();
        }
    }
    
    public static int getTabbedTextOffset(Segment segment, FontMetrics metrics, int tabBase,int x,TabExpander e, int startOffset){
        List<Segment> segments=new ArrayList<Segment>();
        List<Boolean> unis=new ArrayList<Boolean>();
        
        Font origFont=metrics.getFont();
        getSegments(origFont, segment, segments, unis);
        Graphics g=new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getGraphics();
        Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
        int ret=0;
        int pos=0;
        for(int i=0;i<segments.size();i++){
            Segment seg=segments.get(i);
            ret += Utilities.getTabbedTextOffset(seg, g.getFontMetrics(unis.get(i)?uniFont:origFont), tabBase,x, e, startOffset+pos);     
            pos += seg.length();
        }
        return ret;
    }
    
    private static void getSegments(Font f,Segment segment,List<Segment> segments,List<Boolean> unis){
       
        int start=0;
        int len=0;
        boolean uni=false;
        for(int i=0;i<segment.length();i++){
            boolean newuni=false;
            if(!f.canDisplay(segment.charAt(i))){               
                newuni=true;
            }
            if(i>0 && uni!=newuni){
                Segment s =new Segment(segment.array, segment.offset+start, len);
                segments.add(s);
                unis.add(uni);
                start = i;
                len=0;
            }
            uni=newuni;
            len++;
        }
        if(len>0){
            Segment s =new Segment(segment.array, segment.offset+start, len);
            segments.add(s);
            unis.add(uni);                
        }  
    }
    
    public static int getTabbedTextWidth(Segment segment,FontMetrics f,int x,TabExpander e, int startOffset){
        Graphics g=new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getGraphics();
        g.setFont(f.getFont());
        return getTabbedTextWidth(g,segment,x,e,startOffset);
    }
    
    public static int getTabbedTextWidth(Graphics g,Segment segment,int x,TabExpander e, int startOffset){
        List<Segment> segments=new ArrayList<Segment>();
        List<Boolean> unis=new ArrayList<Boolean>();
        getSegments(g.getFont(), segment, segments, unis);
        Font origFont=g.getFont();
        Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
        int ret=0;
        int pos=0;
        for(int i=0;i<segments.size();i++){
            Segment seg=segments.get(i);
            ret += Utilities.getTabbedTextWidth(seg, g.getFontMetrics(unis.get(i)?uniFont:origFont), 0, e, startOffset+pos);     
            pos += seg.length();
        }
        return ret;       
    }
    
    public static int drawTabbedText(Segment segment, int x, int y, Graphics g, TabExpander e, int startOffset){
        
        List<Segment> segments=new ArrayList<Segment>();
        List<Boolean> unis=new ArrayList<Boolean>();
        getSegments(g.getFont(), segment, segments, unis);
        Font origFont=g.getFont();
        Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
        int ret=x;
        int pos=0;
        for(int i=0;i<segments.size();i++){
            Segment seg=segments.get(i);
            if(unis.get(i)){
                g.setFont(uniFont);
            }else{
                g.setFont(origFont);
            }
            ret = Utilities.drawTabbedText(seg, ret, y, g, e, startOffset+pos);   
            pos += seg.length();
        }
        g.setFont(origFont);
        return ret;         
    }
    
    public static int stringWidth(Graphics g,String string){
        List<Segment> segments=new ArrayList<Segment>();
        List<Boolean> unis=new ArrayList<Boolean>();
        Segment segment=new Segment(string.toCharArray(), 0, string.length());
        getSegments(g.getFont(), segment, segments, unis);
        Font origFont=g.getFont();
        Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
        int ret=0;
        for(int i=0;i<segments.size();i++){
            Segment seg=segments.get(i);
            ret+=g.getFontMetrics(unis.get(i)?uniFont:origFont).stringWidth(seg.toString());
        }
        return ret;
    }
}
