package basics.utl;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import basics.testing.Test;
import basics.unexpected.Problem;

public class FormatterUtl
{
private FormatterUtl()
{
}

//@check this!!!
public static synchronized String format(double value, int digits, int precision)
{
   StringBuilder sb = new StringBuilder();
   String v = String.valueOf(value);
   String [] parts = v.split("\\.");
   String l = parts == null || parts.length > 0 ? parts[0] : "";
   sb.append(FormatterUtl.padl(l, "0", digits));
   if(precision > 0)
   {
      sb.append(".");
      String r = parts == null || parts.length < 2 ? "" : parts[1];
      if(r.length() > precision)
      {
         sb.append(r.substring(0, precision));
      }
      else
      {
         sb.append(FormatterUtl.padr(r, "0", precision));
      }
   }
   return sb.toString();
}

public static synchronized String format(double value, int digits)
{
   StringBuilder sb = new StringBuilder();
   String v = String.valueOf(value);
   String [] parts = v.split("\\.");
   String l = parts == null || parts.length > 0 ? parts[0] : "";
   sb.append(FormatterUtl.padl(l, "0", digits));
   return sb.toString();
}

public static String formatBytesPadLeft(long bytes, int padding)
{
   if(bytes == 0)
      return "";
   if(bytes > 999)
   {
      double b = (double)bytes / 1024d; // s
      if(b > 999d)
      {
         b /= 1024d; // m
         if(b > 999d)
         {
            b /= 1024d; // h
            return FormatterUtl.padl(NumUtl.round(b, 1) + "G", " ", padding);
         }
         else
            return FormatterUtl.padl(NumUtl.round(b, 1) + "M", " ", padding);
      }
      else
         return FormatterUtl.padl(NumUtl.round(b, 1) + "K", " ", padding);
   }
   else
      return FormatterUtl.padl(bytes + "b ", " ", padding - 1);
}

public static String formatMillisPadLeft(long millis, int padding)
{
   if(millis > 999)
   {
      double t = (double)millis / 1000d; // s
      if(t > 100d)
      {
         t /= 60d; // m
         if(t > 100d)
         {
            t /= 60d; // h
            return FormatterUtl.padl(NumUtl.round(t, 1) + "h", " ", padding);
         }
         else
            return FormatterUtl.padl(NumUtl.round(t, 1) + "m", " ", padding);
      }
      else
         return FormatterUtl.padl(NumUtl.round(t, 1) + "s", " ", padding);
   }
   else
      return FormatterUtl.padl(millis + " ms", " ", padding);
}

public static String proper(String input)
{
   if(input == null)
      return null;
   if(input.length() < 1)
      return "";
   String output = input.toLowerCase();
   String i = output.substring(0, 1).toUpperCase();
   return i + output.substring(1, output.length());
}

public static String padl(String buffer, String sign, int minWidth)
{
   StringBuilder res = new StringBuilder();
   int x = minWidth - buffer.length();
   for(int i = 0; i < x; i++)
      res.append(sign);
   res.append(buffer);
   buffer = res.toString();
   return buffer;
}

public static String padr(String buffer, String sign, int minWidth)
{
   StringBuilder res = new StringBuilder();
   int x = minWidth - buffer.length();
   res.append(buffer);
   for(int i = 0; i < x; i++)
      res.append(sign);
   buffer = res.toString();
   return buffer;
}

public static String removeWhitespaceTail(String text)
{
   if(text == null)
      return text;
   int signs = text.length();
   int cutpos = -1;
   for(int i = signs - 1; i >= 0; i--)
   {
      String tail = text.substring(i, i + 1);
      if(tail.matches("\\s"))
         cutpos = i;
      else
         break;
   }
   if(cutpos > -1)
      text = text.substring(0, cutpos);
   return text;
}

public static String shortenNumber(long num)
{
   if(num == 0)
      return "0";
   if(num < 1000)
      return num + "";
   double b = (double)num / 1000d; // K
   if(b < 1000)
      return NumUtl.round(b, 1) + "K";
   b /= 1000d; // K
   if(b < 1000)
      return NumUtl.round(b, 1) + "M";
   b /= 1000d; // G
   if(b < 1000)
      return NumUtl.round(b, 1) + "G";
   b /= 1000d; // T
   if(b < 1000)
      return NumUtl.round(b, 1) + "T";
   b /= 1000d; // P
   return NumUtl.round(b, 1) + "P";
}

public static String simpleName(String className)
{
   String r = SUtl.$(className);
   int x = r.lastIndexOf(".");
   return x == -1 ? r : r.substring(x + 1);
}

public static String packageName(String className)
{
   String r = SUtl.$(className);
   int x = r.lastIndexOf(".");
   return x == -1 ? r : r.substring(0, x);
}

// untested ----------------------
public static String stackTraceToString(Throwable aThrowable)
{
   final Writer result = new StringWriter();
   final PrintWriter printWriter = new PrintWriter(result);
   aThrowable.printStackTrace(printWriter);
   String s = result.toString();
   s = SUtl.replaceAll(s, Problem.class.getName() + ":", "");
   s = s.replaceAll("at .*\\(", " <= (");
   s = SUtl.xtrim(s);
   s = s.replaceAll(" {2,}", " ");
   return s;
}

public static String tag(String tag, String content)
{
   StringBuilder s = new StringBuilder();
   s.append("<");
   s.append(tag);
   s.append(">");
   s.append(content);
   s.append("</");
   s.append(tag);
   s.append(">");
   return s.toString();
}

public static String timestring(long t)
{
   double v = t;
   String unit = "ms";
   if(v > 10000)
   {
      v /= 1000;
      unit = "s";
      if(v > 360)
      {
         v /= 60;
         unit = "m";
         if(v > 120)
         {
            v /= 60;
            unit = "h";
         }
      }
   }
   String r = v + "";
   if(r.indexOf(".") > -1)
   {
      r = r.substring(0, r.indexOf(".") + 2);
   }
   else
      r += ".0";
   return r + unit;
}

public static void unittest()
{
   Test
      .assertEqualsTrue(padl("a", " ", 3), "  a", "'  a' expected not '" + padl("a", " ", 3) + "'");
   Test
      .assertEqualsTrue(padr("a", " ", 3), "a  ", "'a  ' expected not '" + padr("a", " ", 3) + "'");
   Test.assertEqualsTrue(format(0.1234, 2), "00", "00 expected not " + format(0.1234, 2));
   Test.assertEqualsTrue(format(0.1234, 2, 3), "00.123", "00.123 expected not "
      + format(0.1234, 2, 3));
   Test.assertEqualsTrue(formatBytesPadLeft(1000000, 10), "    976.6K",
      "'    976.6K' expected not '" + formatBytesPadLeft(1000000, 10) + "'");
   Test.assertEqualsTrue(formatMillisPadLeft(1000, 6), "  1.0s", "'  1.0s' expected not '"
      + formatMillisPadLeft(1000, 6) + "'");
   Test.assertEqualsTrue(proper("hallo hallo"), "Hallo hallo", "'Hallo hallo' expected not '"
      + proper("hallo hallo") + "'");
   Test.assertEqualsTrue(removeWhitespaceTail(" hallo hallo \t\n "), " hallo hallo",
      "' hallo hallo' expected not '" + removeWhitespaceTail(" hallo hallo \t\n ") + "'");
   Test.assertEqualsTrue(shortenNumber(1234567890), "1.2T", "'1.2T' expected not '"
      + shortenNumber(1234567890) + "'");
   Test.assertEqualsTrue(shortenNumber(1234567), "1.2M", "'1.2M' expected not '"
      + shortenNumber(1234567) + "'");
   Test.assertEqualsTrue(tag("tag", "content"), "<tag>content</tag>",
      "'<tag>content</tag>' expected not '" + tag("tag", "content") + "'");
   Test.assertEqualsTrue(simpleName("java.util.String"), "String", "'String' expected not '"
      + simpleName("java.util.String") + "'");
   Test.assertEqualsTrue(packageName("java.util.String"), "java.util", "'java.util' expected not '"
      + packageName("java.util.String") + "'");
   Test.assertEqualsTrue(timestring(1234567890), "342.9h", "'342.9h' expected not '"
      + timestring(1234567890) + "'");
   Test.assertEqualsTrue(timestring(123), "123.0ms", "'123.0ms' expected not '" + timestring(123)
      + "'");
   Test.assertEqualsTrue(timestring(16001), "16.0s", "'16.0s' expected not '" + timestring(16001)
      + "'");
}
}
