package p03_zmienne_i_typy;

public class Rzutowania {

    // "Hierarchia" typów prostych:
    // byte < short < int < long < float < double
    // char < int

    public static void main(String[] args) {
        int x = 107;
        float f = 3.14f;
        long l3 = 13;

        // rzutowanie niejawne - na zmienną typu "szerszego" można zapisać wartość typu "węższego" (widening)
        long l = x;
        float f2 = l3;
        //NK x = l;
        //NK l = f;
        f = l;

        // rzutowanie jawne można stosować zawsze; czasem może wiązać się z "popsuciem" wartości liczbowej
        x = (int)l;
        System.out.println(x);

        // można stosować jawne rzutowanie nawet gdy nie jest konieczne
        l = x;
        l = (long)x;
        System.out.println(l);

        l = 4_000_000_000L;
        x = (int)l;
        System.out.println(x); // zmieniona wartość, ostatnie 32 bity z zapisu tej liczby

        f = 100.99F;
        x = (int)f; // obcina do wartości całkowitej
        System.out.println(x); // 100

        f = 4e9f; // 4 * 10^9 czyli 4mld
        x = (int)f; // po wyjściu poza zakres przyjmuje MAXINT / MININT
        System.out.println(x);

        // Na zmienne typu byte, short i char można wpisywać konkretne wartości całkowite, o ile kompilator widzi, że mieszczą się w zakresie

        byte b1 = 100;
        //NK byte b2 = 200;

        x = 100;
        //NK byte b3 = x;

        final int fi = 10;
        b1 = fi; // jeśli wartość jest "stałą" (jest final i jest znana w czasie kompilacji)

        b1 = 50;
        //NK b1 = x; // bo "nie każdy int mieści się w byte"
        x = b1; // OK, bo byte mieści się w int

        //NK int i3 = 3L;

        float f3 = 3L;

        byte b = 13;
        b = 15;
        //NK b = 130;

        x = 15;
        //NK b = x;
        b = (byte)x;

        //NK wezByte(88);
        wezByte((byte)88);
        wezByte(b);
        System.out.println();

        System.out.println(dajByte());
        System.out.println(dajZnak());
        System.out.println();

        l = 5_000_000_000L;
        x = (int)l;
        System.out.println(x);
        // rzutowanie liczb całkowitych - bierzemye ostatnie bity z zapisu liczby w pamięci
        // zobaczę to samo, co w int overflow gdy mnożyłem 5 * 1000000000
        System.out.println("5mld long   rzut na int: " + x);

        double d = 5_000_000_000.0;
        x = (int)d;
        System.out.println("5mld double rzut na int: " + x);
        // rzutowanie float i double na liczbę całkowitą - bierzemy wartość, która jest najbliżej,
        // w tym przypadku będzie to Integer.MAX_VALUE

        byte b2 = 40, b3 = 50;

        // Operacje arytmetyczne + - * / %  - są zdefiniowane dla typu int, a nie dla byte i short
        // dlatego ich ywniki trzeba zrzutowa, aby pisać na zmienne tych typów
        //NK byte b4 = b2 + b3;
        byte b4 = (byte)(b2 + b3);

        // ale bez rzutowania działają ++ i +=

        System.out.println(b2);
        b2++;
        System.out.println(b2);

        b2 += 10;
        System.out.println(b2);
    }

    static byte dajByte() {
        return 65;
    }

    /* NK
    static byte dajByteInaczej() {
    	int x = 65;
    	return x;
    }
    */

    static char dajZnak() {
        return 65;
    }

    static void wezByte(byte bbb) {
        System.out.println(bbb);
    }

}
