package com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Log;

import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;

import com.teamopensmartglasses.smartglassesmanager.R;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
import com.vuzix.ultralite.Anchor;
import com.vuzix.ultralite.EventListener;
import com.vuzix.ultralite.Layout;
import com.vuzix.ultralite.TextAlignment;
import com.vuzix.ultralite.TextWrapMode;
import com.vuzix.ultralite.UltraliteColor;
import com.vuzix.ultralite.UltraliteSDK;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;


//communicate with ActiveLook smart glasses
public class UltraliteSGC extends SmartGlassesCommunicator {
    private static final String TAG = "WearableAi_UltraliteSGC";

    UltraliteSDK ultraliteSdk;
    UltraliteSDK.Canvas ultraliteCanvas;
    UltraliteListener ultraliteListener;
    Layout currentUltraliteLayout;
    boolean screenToggleOff = false; //should we keep the screen off?
    LifecycleOwner lifecycleOwner;
    Context context;
    public static final int cardLingerTime = 15;

    private ArrayList rowTextsLiveNow;

    //ultralite pixel buffer on left side of screen
    int ultraliteLeftSidePixelBuffer = 40;

    // Constants for maximum lines and characters per line //depends on size of pixel buffer! //for MEDIUM text!
    private int maxLines = 12; // Adjusted from 11.5 for practical use
    private int maxCharsPerLine = 38; // Assuming max 27 characters fit per line on your display

    //handler to turn off screen
    Handler goHomeHandler;
    Runnable goHomeRunnable;

    //handler to turn off screen/toggle
    Handler screenOffHandler;
    Runnable screenOffRunnable;

    //handler to disconnect
    Handler killHandler;

    boolean hasUltraliteControl;
    boolean screenIsClear;

    public class UltraliteListener implements EventListener{
        @Override
        public void onTap(int tapCount) {
            Log.d(TAG, "Ultralite go tap n times: " + tapCount);
            tapEvent(tapCount);
        }

        @Override
        public void onDisplayTimeout() {
            Log.d(TAG, "Ultralite display timeout.");
        }

        @Override
        public void onPowerButtonPress(boolean turningOn) {
            //since we implement our own state for the power turn on/off, we ignore what the ultralite thinks ('turningOn') and use our own state
            Log.d(TAG, "Ultralites power button pressed: " + turningOn);

            //flip value of screen toggle
            screenToggleOff = !turningOn;

            if (!screenToggleOff) {
                Log.d(TAG, "screen toggle off NOT on, showing turn ON message");
                displayReferenceCardSimple("SGM Connected.", "Screen back on...", 4);
            } else {
                Log.d(TAG, "screen toggle off IS on, showing turn OFF message");
//                ultraliteCanvas.clear();
//                displayReferenceCardSimple("Toggling off....", "Toggling off...", -1);
//                screenOffHandler.removeCallbacksAndMessages(this);
//                screenOffHandler.removeCallbacksAndMessages(screenOffRunnable);
//                screenOffRunnable = new Runnable() {
//                    @Override
//                    public void run() {
//                        ultraliteSdk.screenOff();
//                    }
//                };
//                screenOffHandler.postDelayed(screenOffRunnable, 2200);
            }
        }
    }

    public UltraliteSGC(Context context, LifecycleOwner lifecycleOwner) {
        super();
        this.lifecycleOwner = lifecycleOwner;
        this.context = context;

        mConnectState = 0;
        hasUltraliteControl = false;
        screenIsClear = true;
        goHomeHandler = new Handler();
        screenOffHandler = new Handler();
        killHandler = new Handler();

        rowTextsLiveNow = new ArrayList<Integer>();

        ultraliteSdk = UltraliteSDK.get(context);
        ultraliteListener = new UltraliteListener();
        ultraliteSdk.addEventListener(ultraliteListener);

        LiveData<Boolean> ultraliteConnectedLive = ultraliteSdk.getConnected();
        ultraliteConnectedLive.observe(lifecycleOwner, isConnected -> {
            onUltraliteConnectedChange(isConnected);
        });

        LiveData<Boolean> ultraliteControlled = ultraliteSdk.getControlledByMe();
        ultraliteControlled.observe(lifecycleOwner, isControlled -> {
            onUltraliteControlChanged(isControlled);
        });

//        if (ultraliteSdk.isAvailable()){
//            Log.d(TAG, "Ultralite SDK is available.");
//        } else {
//            Log.d(TAG, "Ultralite SDK is NOT available.");
//        }
    }

    private void onUltraliteConnectedChange(boolean isConnected) {
        Log.d(TAG, "Ultralite CONNECT changed to: " + isConnected);
        if (isConnected) {
            Log.d(TAG, "Ultralite requesting control...");
            boolean isControlled = ultraliteSdk.requestControl();
            if (isControlled){
//                setupUltraliteCanvas();
                changeUltraliteLayout(Layout.CANVAS);
            } else {
                return;
            }
            Log.d(TAG, "Ultralite RESULT control request: " + isControlled);
            connectionEvent(2);
        } else {
            Log.d(TAG, "Ultralite not connected.");
            connectionEvent(0);
        }
    }

    private void onUltraliteControlChanged(boolean isControlledByMe) {
        Log.d(TAG, "Ultralite CONTROL changed to: " + isControlledByMe);
        if(isControlledByMe) {
            hasUltraliteControl = true;
            setupUltraliteCanvas();
            connectionEvent(2);
            displayReferenceCardSimple("Connected to SGM", "by TeamOpenSmartGlasses", 5);
        } else {
            hasUltraliteControl = false;
        }
//        mUltraliteControlledByMe = isControlledByMe;
    }

    @Override
    protected void setFontSizes(){
    }

    @Override
    public void connectToSmartGlasses(){
        Log.d(TAG, "connectToSmartGlasses running...");
//        int mCount = 10;
//        while ((mConnectState != 2) && (!hasUltraliteControl) && (mCount > 0)){
//            mCount--;
//            try {
//                Log.d(TAG, "Don't have Ultralite yet, let's wait for it...");
//                Thread.sleep(200);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//        Log.d(TAG, "Connected to Ultralites.");
//        Log.d(TAG, "mCOnnectestate: " + mConnectState);
//        Log.d(TAG, "mCOunt: " + mCount);
//        displayReferenceCardSimple("Connected to SGM.", "Authors: TeamOpenSmartGlasses");
//        connectionEvent(mConnectState);
        Log.d(TAG, "connectToSmartGlasses finished");
    }

    public void displayTextLine(String text){
        displayReferenceCardSimple("", text);
    }

    private static final int MAX_LINES = 7;
    public void displayTextWall(String text) {
        String cleanedText = cleanText(text);

        if (screenToggleOff) {
            return;
        }

        goHomeHandler.removeCallbacksAndMessages(null);
        goHomeHandler.removeCallbacksAndMessages(goHomeRunnable);

        Log.d(TAG, "Ultralite is doing text wall");

        // Cut text wall down to the largest number of lines possible to display
        String[] lines = cleanedText.split("\n");
        StringBuilder truncatedText = new StringBuilder();
        for (int i = 0; i < Math.min(lines.length, MAX_LINES); i++) {
            truncatedText.append(lines[i]).append("\n");
        }

//        changeUltraliteLayout(Layout.TEXT_BOTTOM_LEFT_ALIGN);
        changeUltraliteLayout(Layout.TEXT_BOTTOM_LEFT_ALIGN);
        ultraliteSdk.sendText(truncatedText.toString().trim());

//        changeUltraliteLayout(Layout.CANVAS);
//        ultraliteCanvas.removeText(0); //remove last text we added
//        Anchor ultraliteAnchor = Anchor.TOP_LEFT;
//        TextAlignment ultraliteAlignment = TextAlignment.LEFT;
//        int textId = ultraliteCanvas.createText(text, ultraliteAlignment, UltraliteColor.WHITE, ultraliteAnchor, ultraliteLeftSidePixelBuffer, 0, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);
////        ultraliteCanvas.createText(title, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, ultraliteLeftSidePixelBuffer, 120, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);
//        Log.d(TAG, "VUZIX TEXT ID: " + textId);
        ultraliteCanvas.commit();
        screenIsClear = false;
    }

    private String cleanText(String input) {
        // Replace Chinese punctuation with English equivalents
        String cleaned = input.replace(" ，", ", ")
                .replace("，", ", ")
                .replace(" 。", ".")
                .replace("。", ".")
                .replace(" ！", "!")
                .replace(" ？", "?")
                .replace("？", "?")
                .replace("：", ":")
                .replace("；", ";")
                .replace("（", "(")
                .replace("）", ")")
                .replace("【", "[")
                .replace("】", "]")
                .replace("“", "\"")
                .replace("”", "\"")
                .replace("、", ",") // No quotes around this one
                .replace("‘", "'")
                .replace("’", "'");

        // Fix contractions: handle spaces around apostrophes
        cleaned = cleaned.replaceAll("\\s+'\\s*", "'");

        // Remove any non-breaking spaces and trim leading/trailing spaces
//        cleaned = cleaned.replace("\u00A0", " ").trim();

        return cleaned;
    }

    public static int countNewLines(String str) {
        int count = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == '\n') {
                count++;
            }
        }
        return count;
    }

    public void displayDoubleTextWall(String textTop, String textBottom) {
        if (screenToggleOff) {
            return;
        }

        textTop = cleanText(textTop);
        textBottom = cleanText(textBottom);

//        if (textBottom.endsWith("\n")) {
//            textBottom = textBottom.substring(0, textBottom.length() - 1);
//        }

        goHomeHandler.removeCallbacksAndMessages(null);
        goHomeHandler.removeCallbacksAndMessages(goHomeRunnable);

//        int rowsTop = 5;
        int rowsTop = 5 - countNewLines(textTop);

        StringBuilder combinedText = new StringBuilder();
        combinedText.append(textTop);

        for (int i = 0; i < rowsTop; i++) {
            combinedText.append("\n");
        }

        StringBuilder bottomBuilder = new StringBuilder(textBottom);

        combinedText.append(bottomBuilder);

        // Display the combined text using TEXT_BOTTOM_LEFT_ALIGN layout
        changeUltraliteLayout(Layout.TEXT_BOTTOM_LEFT_ALIGN);
        // ultraliteSdk.sendText(combinedText.toString().trim());
        ultraliteSdk.sendText(combinedText.toString());
        ultraliteCanvas.commit();
        screenIsClear = false;
    }

    public void displayCenteredText(String text){
    }

    public void displayCustomContent(String json) {
        displayReferenceCardSimple("CustomDisplayNotImplemented", json);
    }


    public void showNaturalLanguageCommandScreen(String prompt, String naturalLanguageInput){
//        int boxDelta = 3;
//
//        if (connectedGlasses != null) {
//            connectedGlasses.clear();
//            showPromptCircle();
//
//            //show the prompt
//            lastLocNaturalLanguageArgsTextView = displayText(new TextLineSG(prompt, SMALL_FONT), new Point(0, 11), true);
//            lastLocNaturalLanguageArgsTextView = new Point(lastLocNaturalLanguageArgsTextView.x, lastLocNaturalLanguageArgsTextView.y + boxDelta); //margin down a tad
//
//            //show the final "finish command" prompt
//            int finishY = 90;
//            displayLine(new Point(0, finishY), new Point(100, finishY));
//            displayText(new TextLineSG(finishNaturalLanguageString, SMALL_FONT), new Point(0, finishY + 2), true);
//
//            //show the natural language args in a scroll box
////            ArrayList<TextLineSG> nli = new ArrayList<>();
////            nli.add(new TextLineSG(naturalLanguageInput, SMALL_FONT));
////            lastLocNaturalLanguageArgsTextView = scrollTextShow(nli, startScrollBoxY.y + boxDelta, finishY - boxDelta);
//        }
    }

    public void updateNaturalLanguageCommandScreen(String naturalLanguageArgs){
//        Log.d(TAG, "Displaynig: " + naturalLanguageArgs);
//        displayText(new TextLineSG(naturalLanguageArgs, SMALL_FONT), new Point(0, lastLocNaturalLanguageArgsTextView.y));
    }

    public void blankScreen(){
//        if (connectedGlasses != null){
//            connectedGlasses.clear();
//        }
    }

    @Override
    public void destroy(){
       if (ultraliteSdk != null){
//           displayReferenceCardSimple("Disconnecting...", "Disconnecting Smart Glasses from SGM");
//
//           //disconnect after slight delay, so our above text gets a chance to show up
//           killHandler.postDelayed(new Runnable() {
//               @Override
//               public void run() {
//                   ultraliteSdk.releaseControl();
//               }
//           }, 800);
           ultraliteSdk.removeEventListener(ultraliteListener);
           ultraliteSdk.releaseControl();
       }
    }

    public void showHomeScreen(){
        changeUltraliteLayout(Layout.CANVAS);
        ultraliteCanvas.clear();
        screenIsClear = true;
    }

    public void setupUltraliteCanvas(){
        Log.d(TAG, "Setting up ultralite canvas");
        if (ultraliteSdk != null) {
            ultraliteCanvas = ultraliteSdk.getCanvas();
        }
    }

    public void changeUltraliteLayout(Layout chosenLayout) {
        //don't update layout if it's already setup
        if (currentUltraliteLayout != null && currentUltraliteLayout == chosenLayout){
            return;
        }

        currentUltraliteLayout = chosenLayout;
        ultraliteSdk.setLayout(chosenLayout, 0, true);

        if (chosenLayout.equals(Layout.CANVAS)){
            if (ultraliteCanvas == null){
                setupUltraliteCanvas();
            }
        }
    }

    public void startScrollingTextViewMode(String title){
        super.startScrollingTextViewMode(title);

        if (ultraliteSdk == null) {
            return;
        }

        //clear the screen
        ultraliteCanvas.clear();
        drawTextOnUltralite(title);
    }

    public String addNewlineEveryNWords(String input, int n) {
        String[] words = input.split("\\s+");
        StringBuilder result = new StringBuilder();

        for (int i = 0; i < words.length; i++) {
            result.append(words[i]);
            if ((i + 1) % n == 0 && i != words.length - 1) {
                result.append("\n");
            } else if (i != words.length - 1) {
                result.append(" ");
            }
        }

        return result.toString();
    }

    public void drawTextOnUltralite(String text){
        //edit the text to add new lines to it because ultralite wrapping doesn't work
        String wrappedText = addNewlineEveryNWords(text, 6);

        //display the title at the top of the screen
        UltraliteColor ultraliteColor = UltraliteColor.WHITE;
        Anchor ultraliteAnchor = Anchor.TOP_LEFT;
        TextAlignment ultraliteAlignment = TextAlignment.LEFT;
        changeUltraliteLayout(Layout.CANVAS);
        ultraliteCanvas.clear();
        ultraliteCanvas.clearBackground(UltraliteColor.DIM);
//        ultraliteCanvas.createText(text, ultraliteAlignment, ultraliteColor, ultraliteAnchor, true);
//        ultraliteCanvas.createText(text, ultraliteAlignment, ultraliteColor, Anchor.BOTTOM_LEFT, 0, 0, -1, 80, TextWrapMode.WRAP, true);
        ultraliteCanvas.createText(wrappedText, ultraliteAlignment, ultraliteColor, ultraliteAnchor, true); //, 0, 0, -1, -1, TextWrapMode.WRAP, true);
        ultraliteCanvas.commit();
        screenIsClear = false;
    }

    public Bitmap getBitmapFromDrawable(Resources res) {
        return BitmapFactory.decodeResource(res, R.drawable.vuzix_shield);
    }

    public void displayReferenceCardSimple(String title, String body){
       displayReferenceCardSimple(title, body, cardLingerTime);
    }

//    public void displayReferenceCardSimple(String title, String body, int lingerTime){
//        if (!isConnected()) {
//            Log.d(TAG, "Not showing reference card because not connected to Ultralites...");
//            return;
//        }
//
////        String [] bulletPoints = {"first one", "second one", "dogs and cats"};
////        displayBulletList("Cool Bullets:", bulletPoints, 15);
//
//            Log.d(TAG, "Sending text to Ultralite SDK: \n" + body);
////            ultraliteSdk.sendText("hello world"); //this is BROKEN in Vuzix ultralite 0.4.2 SDK - crashes Vuzix OEM Platform android app
//
//        //edit the text to add new lines to it because ultralite wrapping doesn't work
////        String titleWrapped = addNewlineEveryNWords(title, 6);
////        String bodyWrapped = addNewlineEveryNWords(body, 6);
//
//        //display the title at the top of the screen
//        UltraliteColor ultraliteColor = UltraliteColor.WHITE;
//        Anchor ultraliteAnchor = Anchor.TOP_LEFT;
//        TextAlignment ultraliteAlignment = TextAlignment.LEFT;
//        changeUltraliteLayout(Layout.CANVAS);
//        ultraliteCanvas.clear();
//        ultraliteCanvas.createText(title, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, ultraliteLeftSidePixelBuffer, 120, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);
//        ultraliteCanvas.createText(body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.MIDDLE_LEFT, ultraliteLeftSidePixelBuffer, 0, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);
//        ultraliteCanvas.commit();
//        screenIsClear = false;
//
//        homeScreenInNSeconds(lingerTime);
//    }

    public void setFontSize(SmartGlassesFontSize fontSize){
        int textSize;
        switch (fontSize){
            case SMALL:
                textSize = 24;
                maxLines = 14;
                maxCharsPerLine = 42;
                break;
            case MEDIUM:
                textSize = 29;
                maxLines = 12; // Adjusted from 11.5 for practical use
                maxCharsPerLine = 38; // Assuming max 27 characters fit per line on your display
                break;
            case LARGE:
                textSize = 40;
                maxLines = 7;
                maxCharsPerLine = 28;
                break;
            default:
                throw new IllegalArgumentException("Unknown font size: " + fontSize);
        }
        ultraliteSdk.setFont(null, 0, textSize);
    }

    public void displayReferenceCardSimple(String titleStr, String bodyStr, int lingerTime){
        if (screenToggleOff){
            return;
        }

        String title = maybeReverseRTLString(titleStr);
        String body = maybeReverseRTLString(bodyStr);
        if (!isConnected()) {
            Log.d(TAG, "Not showing reference card because not connected to Ultralites...");
            return;
        }

        changeUltraliteLayout(Layout.CANVAS);
        ultraliteCanvas.clear();

//        String [] bulletPoints = {"first one", "second one", "dogs and cats"};
//        displayBulletList("Cool Bullets:", bulletPoints, 15);

            Log.d(TAG, "Sending text to Ultralite SDK: \n" + body);
//            ultraliteSdk.sendText("hello world"); //this is BROKEN in Vuzix ultralite 0.4.2 SDK - crashes Vuzix OEM Platform android app

        //edit the text to add new lines to it because ultralite wrapping doesn't work
//        String titleWrapped = addNewlineEveryNWords(title, 6);
//        String bodyWrapped = addNewlineEveryNWords(body, 6);

        //display title top of scren adn text middle of screen
//        UltraliteColor ultraliteColor = UltraliteColor.WHITE;
//        Anchor ultraliteAnchor = Anchor.TOP_LEFT;
//        TextAlignment ultraliteAlignment = TextAlignment.LEFT;
//        ultraliteCanvas.createText(title, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, ultraliteLeftSidePixelBuffer, 120, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);
//        ultraliteCanvas.createText(body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.MIDDLE_LEFT, ultraliteLeftSidePixelBuffer, 0, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);

        //concat body and title, put text on top right of screen (to not block main view)
        UltraliteColor ultraliteColor = UltraliteColor.WHITE;
        Anchor ultraliteAnchor = Anchor.TOP_CENTER;
        TextAlignment ultraliteAlignment = TextAlignment.LEFT;
        //ultraliteCanvas.createText(body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_RIGHT, 0, 0, (640 / 2) - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);
        if (!title.isEmpty() && !title.equals("")){
            ultraliteCanvas.createText(title + ": " + body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_RIGHT, 0, 0, 640 / 2, -1, TextWrapMode.WRAP, true);
        } else {
            ultraliteCanvas.createText(body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_RIGHT, 0, 0, 640 / 2, -1, TextWrapMode.WRAP, true);
        }

        //NOTE:
//        int createText(@NonNull
//                String text,
//                @NonNull
//                        TextAlignment alignment,
//                @NonNull
//                        UltraliteColor color,
//                @NonNull
//                        Anchor anchor,
//        int offsetX,
//        int offsetY,
//        int width,
//        int height,
//        @Nullable
//        TextWrapMode wrap,
//        boolean visible)

        ultraliteCanvas.commit();
        screenIsClear = false;

        homeScreenInNSeconds(lingerTime);
    }


    public void displayBulletList(String title, String [] bullets){
        displayBulletList(title, bullets, 14);
    }

    public void displayRowsCard(String[] rowStrings){
        displayRowsCard(rowStrings, cardLingerTime);
    }

    public void displayRowsCard(String[] rowStringList, int lingerTime){
        if (screenToggleOff){
            return;
        }

        String[] rowStrings = maybeReverseRTLStringList(rowStringList);
        if (!isConnected()) {
            Log.d(TAG, "Not showing rows card because not connected to Ultralites...");
            return;
        }

//        changeUltraliteLayout(Layout.CANVAS);
//        ultraliteCanvas.clear();

        //make lines to draw on screen to delineate rows
        int line_thickness = 3;
        for (int y = 120; y < 480; y += 120) {
            ultraliteCanvas.clearBackgroundRect(0, y, 640, line_thickness, UltraliteColor.DIM);
        }

        //clear old text
        for (int i = 0; i < rowTextsLiveNow.size(); i++){
            ultraliteCanvas.removeText(i);
        }
        //old way to clear old text - vuzix ultralite sdk bug that clear background doesn't clear text?
//        for (int y = 0; y < 480; y += 120) {
//            //clear previous text
//            ultraliteCanvas.clearBackgroundRect(0, y + line_thickness, 640, 120 - line_thickness, UltraliteColor.DIM);
//            ultraliteCanvas.clearBackgroundRect(0, y + line_thickness, 640, 120 - line_thickness, UltraliteColor.BLACK);
//        }
//        ultraliteCanvas.commit();

        //display the title at the top of the screen
        UltraliteColor ultraliteColor = UltraliteColor.WHITE;
        Anchor ultraliteAnchor = Anchor.TOP_LEFT;
        TextAlignment ultraliteAlignment = TextAlignment.LEFT;

        //if no input, just show the lines
        if (rowStrings.length == 0){
            ultraliteCanvas.commit();
            screenIsClear = false;
//            homeScreenInNSeconds(lingerTime);
            return;
        }

        //go throw rows, draw the text, don't do more than 4
        int y_start_height = 55;
        // Reverse rowStrings array
        Collections.reverse(Arrays.asList(rowStrings));
        int numRows = 4;
        int actualRows = Math.min(rowStrings.length, numRows);
        for (int i = 0; i < actualRows; i++) {
            // Calculate the offset to start from the bottom for 1, 2, or 3 values
            int yOffset = (numRows - actualRows) * 112;
            int textId = ultraliteCanvas.createText(rowStrings[i], TextAlignment.CENTER, UltraliteColor.WHITE, Anchor.TOP_LEFT, ultraliteLeftSidePixelBuffer, y_start_height + yOffset + (i * 112), 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);
            rowTextsLiveNow.add(textId);
        }

        ultraliteCanvas.commit();
        screenIsClear = false;
//        homeScreenInNSeconds(cardLingerTime);
    }

    public void displayBulletList(String title, String [] bulletList, int lingerTime){
        if (screenToggleOff){
            return;
        }

        String[] bullets = maybeReverseRTLStringList(bulletList);
        if (!isConnected()) {
            Log.d(TAG, "Not showing bullet point list because not connected to Ultralites...");
            return;
        }

        Log.d(TAG, "Sending bullets to Ultralite SDK: " + title);

        //display the title at the top of the screen
        UltraliteColor ultraliteColor = UltraliteColor.WHITE;
        Anchor ultraliteAnchor = Anchor.TOP_LEFT;
        TextAlignment ultraliteAlignment = TextAlignment.LEFT;
        changeUltraliteLayout(Layout.CANVAS);
        ultraliteCanvas.clear();

        ultraliteCanvas.createText(title, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, 0, 0, 640, -1, TextWrapMode.WRAP, true);
        int displaceY = 25;
        int displaceX = 25;
        for (String bullet : bullets){
            ultraliteCanvas.createText("⬤ " + bullet, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, displaceX, displaceY, 640 - displaceX, -1, TextWrapMode.WRAP, true);
            displaceY += 125;
        }

        ultraliteCanvas.commit();
        screenIsClear = false;

//        if (lingerTime > 0){
//            homeScreenInNSeconds(lingerTime);
//        }
    }

    public void homeScreenInNSeconds(int n){
        if (n == -1){
            return;
        }

       //disconnect after slight delay, so our above text gets a chance to show up
       goHomeHandler.removeCallbacksAndMessages(null);
       goHomeHandler.removeCallbacksAndMessages(goHomeRunnable);
       goHomeRunnable = new Runnable() {
           @Override
           public void run() {
               showHomeScreen();
        }};
       goHomeHandler.postDelayed(goHomeRunnable, n * 1000);
    }

    public void displayBitmap(Bitmap bmp) {
        Bitmap resizedBmp = Bitmap.createScaledBitmap(bmp, 620, 460, true); // 640 x 480

        changeUltraliteLayout(Layout.CANVAS);
        screenIsClear = false;

        Log.d(TAG, "Sending bitmap to Ultralite");
        ultraliteCanvas.drawBackground(resizedBmp, 50, 80);
        ultraliteCanvas.commit();
    }

    //don't show images on activelook (screen is too low res)
    public void displayReferenceCardImage(String title, String body, String imgUrl){
        if (screenToggleOff){
            return;
        }

        changeUltraliteLayout(Layout.CANVAS);
        ultraliteCanvas.clear();

        //make image
        //below works, but only for very, very low res/size images
        Anchor ultraliteImageAnchor = Anchor.CENTER;
        Picasso.get()
                .load(imgUrl)
                .into(new Target() {
                    @Override
                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                        // Use the bitmap
//                        LVGLImage ultraliteImage = LVGLImage.fromBitmap(getBitmapFromDrawable(context.getResources()), CF_INDEXED_2_BIT);
//                        LVGLImage ultraliteImage = LVGLImage.fromBitmap(bitmap, CF_INDEXED_2_BIT);
                        changeUltraliteLayout(Layout.CANVAS);

                        //send text first, cuz this is fast
                        ultraliteCanvas.createText(title, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, 0, 0, 640, -1, TextWrapMode.WRAP, true);
                        ultraliteCanvas.createText(body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.BOTTOM_LEFT, 0, 0, 640, -1, TextWrapMode.WRAP, true);
                        ultraliteCanvas.commit();
                        screenIsClear = false;

                        Log.d(TAG, "Sending image to Ultralite");
//                        ultraliteCanvas.createImage(ultraliteImage, ultraliteImageAnchor, 0, 0, true);
                        ultraliteCanvas.drawBackground(bitmap, 0, 0);

                        //sending text again to ultralite in case image overwrote it
//                        ultraliteCanvas.createText(title + "2", TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.BOTTOM_LEFT, 0, 0, 640, -1, TextWrapMode.WRAP, true);
//                        ultraliteCanvas.createText(body + "2", TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.MIDDLE_LEFT, 0, 0, 640, -1, TextWrapMode.WRAP, true);
//                        ultraliteCanvas.commit();

//                        //display the title at the top of the screen
//                        UltraliteColor ultraliteColor = UltraliteColor.WHITE;
//                        TextAlignment ultraliteAlignment = TextAlignment.LEFT;
//                //        ultraliteCanvas.clearBackground(UltraliteColor.DIM);
//                        ultraliteCanvas.createText(titleWrapped, ultraliteAlignment, ultraliteColor, Anchor.TOP_LEFT, true); //, 0, 0, -1, -1, TextWrapMode.WRAP, true);
//                        ultraliteCanvas.createText(bodyWrapped, ultraliteAlignment, ultraliteColor, Anchor.BOTTOM_LEFT, true); //, 0, 0, -1, -1, TextWrapMode.WRAP, true);
//                        ultraliteCanvas.commit();



//                        homeScreenInNSeconds(cardLingerTime);
                    }

                    @Override
                    public void onBitmapFailed(Exception e, Drawable errorDrawable) {
                        // Handle the error
                        Log.d(TAG, "Bitmap failed");
                        e.printStackTrace();
                    }

                    @Override
                    public void onPrepareLoad(Drawable placeHolderDrawable) {
                        // Called before the image is loaded. You can set a placeholder if needed.
                    }
                });

            //edit the text to add new lines to it because ultralite wrapping doesn't work
//            String titleWrapped = addNewlineEveryNWords(title, 6);
//            String bodyWrapped = addNewlineEveryNWords(body, 6);
//
//            //display the title at the top of the screen
//            UltraliteColor ultraliteColor = UltraliteColor.WHITE;
//            TextAlignment ultraliteAlignment = TextAlignment.LEFT;
//            //ultraliteCanvas.clearBackground(UltraliteColor.DIM);
//            ultraliteCanvas.createText(titleWrapped, ultraliteAlignment, ultraliteColor, Anchor.TOP_LEFT, true); //, 0, 0, -1, -1, TextWrapMode.WRAP, true);
//            ultraliteCanvas.createText(bodyWrapped, ultraliteAlignment, ultraliteColor, Anchor.BOTTOM_LEFT, true); //, 0, 0, -1, -1, TextWrapMode.WRAP, true);
//            ultraliteCanvas.commit();
//            screenIsClear = false;
    }

    //handles text wrapping, returns final position of last line printed
//    private Point displayText(TextLineSG textLine, Point percentLoc, boolean centered){
//        if (!isConnected()){
//            return null;
//        }
//
//        //get info about the wrapping
//        Pair wrapInfo = computeStringWrapInfo(textLine);
//        int numWraps = (int)wrapInfo.first;
//        int wrapLenNumChars = (int)wrapInfo.second;
//
//        //loop through the text, writing out individual lines to the glasses
//        ArrayList<String> chunkedText = new ArrayList<>();
//        Point textPoint = percentLoc;
//        int textMarginY = computeMarginPercent(textLine.getFontSizeCode()); //(fontToSize.get(textLine.getFontSize()) * 1.3)
//        for (int i = 0; i <= numWraps; i++){
